5893 lines
194 KiB
Diff
5893 lines
194 KiB
Diff
From 148f2f6e1142f9d2caa9612dd9a68069426537f8 Mon Sep 17 00:00:00 2001
|
|
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
|
|
Date: Fri, 9 Aug 2013 20:13:11 +0300
|
|
Subject: [PATCH 1/4] Changes to make libgambatte rerecording friendly
|
|
|
|
---
|
|
Makefile | 10 +
|
|
libgambatte/Makefile | 18 ++
|
|
libgambatte/include/gambatte.h | 68 ++++++-
|
|
libgambatte/src/bitmap_font.cpp | 10 +-
|
|
libgambatte/src/bitmap_font.h | 6 +-
|
|
libgambatte/src/cpu.cpp | 42 ++++-
|
|
libgambatte/src/cpu.h | 27 ++-
|
|
libgambatte/src/file/file.cpp | 34 ++++
|
|
libgambatte/src/file/file.h | 10 +
|
|
libgambatte/src/gambatte.cpp | 127 +++++++++++--
|
|
libgambatte/src/initstate.cpp | 8 +-
|
|
libgambatte/src/initstate.h | 8 +-
|
|
libgambatte/src/interrupter.cpp | 17 +-
|
|
libgambatte/src/interrupter.h | 17 +-
|
|
libgambatte/src/interruptrequester.cpp | 23 ++-
|
|
libgambatte/src/interruptrequester.h | 23 ++-
|
|
libgambatte/src/loadsave.cpp | 266 +++++++++++++++++++++++++++
|
|
libgambatte/src/loadsave.h | 160 ++++++++++++++++
|
|
libgambatte/src/mem/cartridge.cpp | 159 +++++++++++++---
|
|
libgambatte/src/mem/cartridge.h | 51 +++--
|
|
libgambatte/src/mem/memptrs.cpp | 38 +++-
|
|
libgambatte/src/mem/memptrs.h | 8 +
|
|
libgambatte/src/mem/rtc.cpp | 56 +++++-
|
|
libgambatte/src/mem/rtc.h | 12 +-
|
|
libgambatte/src/memory.cpp | 104 +++++++----
|
|
libgambatte/src/memory.h | 87 +++++----
|
|
libgambatte/src/minkeeper.h | 29 ++-
|
|
libgambatte/src/savestate.h | 47 ++---
|
|
libgambatte/src/sound.cpp | 33 +++-
|
|
libgambatte/src/sound.h | 20 +-
|
|
libgambatte/src/sound/channel1.cpp | 45 ++++-
|
|
libgambatte/src/sound/channel1.h | 29 ++-
|
|
libgambatte/src/sound/channel2.cpp | 40 +++-
|
|
libgambatte/src/sound/channel2.h | 16 +-
|
|
libgambatte/src/sound/channel3.cpp | 41 ++++-
|
|
libgambatte/src/sound/channel3.h | 26 ++-
|
|
libgambatte/src/sound/channel4.cpp | 59 ++++--
|
|
libgambatte/src/sound/channel4.h | 39 ++--
|
|
libgambatte/src/sound/duty_unit.cpp | 34 +++-
|
|
libgambatte/src/sound/duty_unit.h | 27 ++-
|
|
libgambatte/src/sound/envelope_unit.cpp | 19 +-
|
|
libgambatte/src/sound/envelope_unit.h | 12 +-
|
|
libgambatte/src/sound/length_counter.cpp | 19 +-
|
|
libgambatte/src/sound/length_counter.h | 12 +-
|
|
libgambatte/src/sound/sound_unit.h | 15 +-
|
|
libgambatte/src/sound/static_output_tester.h | 8 +-
|
|
libgambatte/src/state_osd_elements.cpp | 8 +-
|
|
libgambatte/src/statesaver.cpp | 4 +-
|
|
libgambatte/src/statesaver.h | 5 +
|
|
libgambatte/src/tima.cpp | 35 ++--
|
|
libgambatte/src/tima.h | 28 +--
|
|
libgambatte/src/video.cpp | 146 ++++++++-------
|
|
libgambatte/src/video.h | 123 +++++++------
|
|
libgambatte/src/video/ly_counter.cpp | 14 +-
|
|
libgambatte/src/video/ly_counter.h | 26 ++-
|
|
libgambatte/src/video/lyc_irq.cpp | 16 +-
|
|
libgambatte/src/video/lyc_irq.h | 27 ++-
|
|
libgambatte/src/video/m0_irq.h | 9 +-
|
|
libgambatte/src/video/next_m0_time.h | 9 +
|
|
libgambatte/src/video/ppu.cpp | 120 +++++++++---
|
|
libgambatte/src/video/ppu.h | 92 ++++++---
|
|
libgambatte/src/video/sprite_mapper.cpp | 17 +-
|
|
libgambatte/src/video/sprite_mapper.h | 53 ++++--
|
|
63 files changed, 2099 insertions(+), 592 deletions(-)
|
|
create mode 100644 Makefile
|
|
create mode 100644 libgambatte/Makefile
|
|
create mode 100644 libgambatte/src/loadsave.cpp
|
|
create mode 100644 libgambatte/src/loadsave.h
|
|
|
|
diff --git a/Makefile b/Makefile
|
|
new file mode 100644
|
|
index 0000000..2714a5b
|
|
--- /dev/null
|
|
+++ b/Makefile
|
|
@@ -0,0 +1,10 @@
|
|
+all: libgambatte/__all_files__
|
|
+
|
|
+libgambatte/__all_files__: forcelook
|
|
+ $(MAKE) -C libgambatte
|
|
+
|
|
+clean: forcelook
|
|
+ $(MAKE) -C libgambatte clean
|
|
+
|
|
+forcelook:
|
|
+ @true
|
|
diff --git a/libgambatte/Makefile b/libgambatte/Makefile
|
|
new file mode 100644
|
|
index 0000000..7c3724e
|
|
--- /dev/null
|
|
+++ b/libgambatte/Makefile
|
|
@@ -0,0 +1,18 @@
|
|
+all: libgambatte.$(ARCHIVE_SUFFIX)
|
|
+
|
|
+REALAR=$(CROSS_PREFIX)ar
|
|
+
|
|
+OBJECTS=$(patsubst %.cpp,%.$(OBJECT_SUFFIX),$(wildcard src/*.cpp src/video/*.cpp src/mem/*.cpp src/sound/*.cpp src/file/file.cpp))
|
|
+
|
|
+%.o: %.cpp
|
|
+ $(gambatte_compiler) $(CFLAGS) -Wno-deprecated-declarations -DHAVE_CSTDINT -I../common -Iinclude -Isrc -c -o $@ $<
|
|
+
|
|
+libgambatte.$(ARCHIVE_SUFFIX): $(OBJECTS)
|
|
+ $(REALAR) crvs $@ $^
|
|
+ $(REALRANLIB) $@
|
|
+
|
|
+clean: forcelook
|
|
+ rm -f $(OBJECTS) libgambatte.$(ARCHIVE_SUFFIX)
|
|
+
|
|
+forcelook:
|
|
+ @true
|
|
\ No newline at end of file
|
|
diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h
|
|
index f1a4633..2901fdf 100644
|
|
--- a/libgambatte/include/gambatte.h
|
|
+++ b/libgambatte/include/gambatte.h
|
|
@@ -24,6 +24,11 @@
|
|
#include "loadres.h"
|
|
#include <cstddef>
|
|
#include <string>
|
|
+#include <vector>
|
|
+
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
|
|
namespace gambatte {
|
|
|
|
@@ -52,6 +57,15 @@ public:
|
|
*/
|
|
LoadRes load(std::string const &romfile, unsigned flags = 0);
|
|
|
|
+ /** Load ROM image.
|
|
+ *
|
|
+ * @param image Raw ROM image data.
|
|
+ * @param isize Size of raw ROM image data.
|
|
+ * @param flags ORed combination of LoadFlags.
|
|
+ * @return 0 on success, negative value on failure.
|
|
+ */
|
|
+ LoadRes load(const unsigned char* image, size_t isize, unsigned flags = 0);
|
|
+
|
|
/**
|
|
* Emulates until at least 'samples' audio samples are produced in the
|
|
* supplied audio buffer, or until a video frame has been drawn.
|
|
@@ -80,8 +94,8 @@ public:
|
|
* @return sample offset in audioBuf at which the video frame was completed, or -1
|
|
* if no new video frame was completed.
|
|
*/
|
|
- std::ptrdiff_t runFor(gambatte::uint_least32_t *videoBuf, std::ptrdiff_t pitch,
|
|
- gambatte::uint_least32_t *audioBuf, std::size_t &samples);
|
|
+ signed runFor(gambatte::uint_least32_t *videoBuf, std::ptrdiff_t pitch,
|
|
+ gambatte::uint_least32_t *soundBuf, unsigned &samples);
|
|
|
|
/**
|
|
* Reset to initial state.
|
|
@@ -93,7 +107,7 @@ public:
|
|
* @param palNum 0 <= palNum < 3. One of BG_PALETTE, SP1_PALETTE and SP2_PALETTE.
|
|
* @param colorNum 0 <= colorNum < 4
|
|
*/
|
|
- void setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32);
|
|
+ void setDmgPaletteColor(int palNum, int colorNum, uint_least32_t rgb32);
|
|
|
|
/** Sets the callback used for getting input state. */
|
|
void setInputGetter(InputGetter *getInput);
|
|
@@ -149,6 +163,16 @@ public:
|
|
*/
|
|
bool loadState(std::string const &filepath);
|
|
|
|
+ /** Save savestate to given buffer.
|
|
+ */
|
|
+ void saveState(std::vector<char>& data, const std::vector<char>& cmpdata);
|
|
+ /** Save savestate to given buffer.
|
|
+ */
|
|
+ void saveState(std::vector<char>& data);
|
|
+ /** Load savestate from given buffer.
|
|
+ */
|
|
+ void loadState(const std::vector<char>& data);
|
|
+
|
|
/**
|
|
* Selects which state slot to save state to or load state from.
|
|
* There are 10 such slots, numbered from 0 to 9 (periodically extended for all n).
|
|
@@ -180,9 +204,45 @@ public:
|
|
*/
|
|
void setGameShark(std::string const &codes);
|
|
|
|
+ /** Set RTC base time.
|
|
+ */
|
|
+ void setRtcBase(time_t time);
|
|
+
|
|
+ /** Get RTC base time.
|
|
+ */
|
|
+ time_t getRtcBase();
|
|
+
|
|
+ /** Get pointer and size to Work RAM.
|
|
+ * @return The pointer and size of Work RAM.
|
|
+ */
|
|
+ std::pair<unsigned char*, size_t> getWorkRam();
|
|
+
|
|
+ /** Get pointer and size to Save RAM.
|
|
+ * @return The pointer and size of Save RAM.
|
|
+ */
|
|
+ std::pair<unsigned char*, size_t> getSaveRam();
|
|
+
|
|
+ /** Get pointer and size to I/O RAM.
|
|
+ * @return The pointer and size of I/O RAM.
|
|
+ */
|
|
+ std::pair<unsigned char*, size_t> getIoRam();
|
|
+
|
|
+ /** Get pointer and size to Video RAM.
|
|
+ * @return The pointer and size of Video RAM.
|
|
+ */
|
|
+ std::pair<unsigned char*, size_t> getVideoRam();
|
|
+
|
|
+ /** Function to get wall time. */
|
|
+ void set_walltime_fn(time_t (*_walltime)());
|
|
+
|
|
+ /** Get version. */
|
|
+ static std::string version();
|
|
private:
|
|
+ void preload_common();
|
|
+ void postload_common(const unsigned flags);
|
|
struct Priv;
|
|
Priv *const p_;
|
|
+ time_t (*walltime)();
|
|
|
|
GB(GB const &);
|
|
GB & operator=(GB const &);
|
|
@@ -190,4 +250,6 @@ private:
|
|
|
|
}
|
|
|
|
+#define GAMBATTE_USES_LOADRES
|
|
+
|
|
#endif
|
|
diff --git a/libgambatte/src/bitmap_font.cpp b/libgambatte/src/bitmap_font.cpp
|
|
index 614f94e..aec5d2e 100644
|
|
--- a/libgambatte/src/bitmap_font.cpp
|
|
+++ b/libgambatte/src/bitmap_font.cpp
|
|
@@ -68,6 +68,10 @@
|
|
gnome dot org.
|
|
*/
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include "bitmap_font.h"
|
|
#include <algorithm>
|
|
|
|
@@ -288,7 +292,7 @@ namespace {
|
|
|
|
class Rgb32Fill {
|
|
public:
|
|
- explicit Rgb32Fill(unsigned long color)
|
|
+ explicit Rgb32Fill(uint_least32_t color)
|
|
: color_(color)
|
|
{
|
|
}
|
|
@@ -298,12 +302,12 @@ public:
|
|
}
|
|
|
|
private:
|
|
- unsigned long const color_;
|
|
+ uint_least32_t const color_;
|
|
};
|
|
|
|
}
|
|
|
|
-void print(gambatte::uint_least32_t *dest, std::ptrdiff_t pitch, unsigned long color, char const *chars) {
|
|
+void print(gambatte::uint_least32_t *dest, std::ptrdiff_t pitch, uint_least32_t color, char const *chars) {
|
|
print(dest, pitch, Rgb32Fill(color), chars);
|
|
}
|
|
|
|
diff --git a/libgambatte/src/bitmap_font.h b/libgambatte/src/bitmap_font.h
|
|
index db83db8..81bc5d0 100644
|
|
--- a/libgambatte/src/bitmap_font.h
|
|
+++ b/libgambatte/src/bitmap_font.h
|
|
@@ -19,6 +19,10 @@
|
|
#ifndef BITMAP_FONT_H
|
|
#define BITMAP_FONT_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include "gbint.h"
|
|
#include <cstddef>
|
|
|
|
@@ -44,7 +48,7 @@ std::size_t getWidth(char const *chars);
|
|
template<class RandomAccessIterator, class Fill>
|
|
void print(RandomAccessIterator dest, std::ptrdiff_t pitch, Fill fill, char const *chars);
|
|
|
|
-void print(gambatte::uint_least32_t *dest, std::ptrdiff_t pitch, unsigned long color, char const *chars);
|
|
+void print(gambatte::uint_least32_t *dest, std::ptrdiff_t pitch, uint_least32_t color, char const *chars);
|
|
void utoa(unsigned u, char *a);
|
|
|
|
// --- INTERFACE END ---
|
|
diff --git a/libgambatte/src/cpu.cpp b/libgambatte/src/cpu.cpp
|
|
index fee943a..06400c5 100644
|
|
--- a/libgambatte/src/cpu.cpp
|
|
+++ b/libgambatte/src/cpu.cpp
|
|
@@ -20,10 +20,14 @@
|
|
#include "memory.h"
|
|
#include "savestate.h"
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
-CPU::CPU()
|
|
-: mem_(Interrupter(sp, pc_))
|
|
+CPU::CPU(time_t (**_getCurrentTime)())
|
|
+: mem_(Interrupter(sp, pc_), _getCurrentTime)
|
|
, cycleCounter_(0)
|
|
, pc_(0x100)
|
|
, sp(0xFFFE)
|
|
@@ -42,10 +46,10 @@ CPU::CPU()
|
|
{
|
|
}
|
|
|
|
-long CPU::runFor(unsigned long const cycles) {
|
|
+signed CPU::runFor(unsigned const cycles) {
|
|
process(cycles);
|
|
|
|
- long const csb = mem_.cyclesSinceBlit(cycleCounter_);
|
|
+ signed const csb = mem_.cyclesSinceBlit(cycleCounter_);
|
|
|
|
if (cycleCounter_ & 0x80000000)
|
|
cycleCounter_ = mem_.resetCounters(cycleCounter_);
|
|
@@ -121,6 +125,26 @@ void CPU::loadState(SaveState const &state) {
|
|
skip_ = state.cpu.skip;
|
|
}
|
|
|
|
+void CPU::loadOrSave(loadsave& state)
|
|
+{
|
|
+ mem_.loadOrSave(state);
|
|
+ state(cycleCounter_);
|
|
+ state(pc_);
|
|
+ state(sp);
|
|
+ state(hf1);
|
|
+ state(hf2);
|
|
+ state(zf);
|
|
+ state(cf);
|
|
+ state(a_);
|
|
+ state(b);
|
|
+ state(c);
|
|
+ state(d);
|
|
+ state(e);
|
|
+ state(h);
|
|
+ state(l);
|
|
+ state(skip_);
|
|
+}
|
|
+
|
|
// The main reasons for the use of macros is to more conveniently be able to tweak
|
|
// which variables are local and which are not, combined with the fact that at the
|
|
// time they were written GCC had a tendency to not be able to keep hot variables
|
|
@@ -485,18 +509,18 @@ void CPU::loadState(SaveState const &state) {
|
|
PC_MOD(high << 8 | low); \
|
|
} while (0)
|
|
|
|
-void CPU::process(unsigned long const cycles) {
|
|
+void CPU::process(unsigned const cycles) {
|
|
mem_.setEndtime(cycleCounter_, cycles);
|
|
|
|
unsigned char a = a_;
|
|
- unsigned long cycleCounter = cycleCounter_;
|
|
+ unsigned cycleCounter = cycleCounter_;
|
|
|
|
while (mem_.isActive()) {
|
|
unsigned short pc = pc_;
|
|
|
|
if (mem_.halted()) {
|
|
if (cycleCounter < mem_.nextEventTime()) {
|
|
- unsigned long cycles = mem_.nextEventTime() - cycleCounter;
|
|
+ unsigned cycles = mem_.nextEventTime() - cycleCounter;
|
|
cycleCounter += cycles + (-cycles & 3);
|
|
}
|
|
} else while (cycleCounter < mem_.nextEventTime()) {
|
|
@@ -591,7 +615,7 @@ void CPU::process(unsigned long const cycles) {
|
|
cycleCounter = mem_.stop(cycleCounter);
|
|
|
|
if (cycleCounter < mem_.nextEventTime()) {
|
|
- unsigned long cycles = mem_.nextEventTime() - cycleCounter;
|
|
+ unsigned cycles = mem_.nextEventTime() - cycleCounter;
|
|
cycleCounter += cycles + (-cycles & 3);
|
|
}
|
|
|
|
@@ -1005,7 +1029,7 @@ void CPU::process(unsigned long const cycles) {
|
|
mem_.halt();
|
|
|
|
if (cycleCounter < mem_.nextEventTime()) {
|
|
- unsigned long cycles = mem_.nextEventTime() - cycleCounter;
|
|
+ unsigned cycles = mem_.nextEventTime() - cycleCounter;
|
|
cycleCounter += cycles + (-cycles & 3);
|
|
}
|
|
}
|
|
diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h
|
|
index 01b82b9..9f9a11e 100644
|
|
--- a/libgambatte/src/cpu.h
|
|
+++ b/libgambatte/src/cpu.h
|
|
@@ -19,16 +19,22 @@
|
|
#ifndef CPU_H
|
|
#define CPU_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include "memory.h"
|
|
+#include "loadsave.h"
|
|
|
|
namespace gambatte {
|
|
|
|
class CPU {
|
|
public:
|
|
- CPU();
|
|
- long runFor(unsigned long cycles);
|
|
+ CPU(time_t (**_getCurrentTime)());
|
|
+ signed runFor(unsigned cycles);
|
|
void setStatePtrs(SaveState &state);
|
|
void saveState(SaveState &state);
|
|
+ void loadOrSave(loadsave& state);
|
|
void loadState(SaveState const &state);
|
|
void loadSavedata() { mem_.loadSavedata(); }
|
|
void saveSavedata() { mem_.saveSavedata(); }
|
|
@@ -57,6 +63,10 @@ public:
|
|
return mem_.loadROM(romfile, forceDmg, multicartCompat);
|
|
}
|
|
|
|
+ LoadRes load(const unsigned char* image, size_t isize, bool forceDmg, bool multicartCompat) {
|
|
+ return mem_.loadROM(image, isize, forceDmg, multicartCompat);
|
|
+ }
|
|
+
|
|
bool loaded() const { return mem_.loaded(); }
|
|
char const * romTitle() const { return mem_.romTitle(); }
|
|
PakInfo const pakInfo(bool multicartCompat) const { return mem_.pakInfo(multicartCompat); }
|
|
@@ -64,23 +74,30 @@ public:
|
|
std::size_t fillSoundBuffer() { return mem_.fillSoundBuffer(cycleCounter_); }
|
|
bool isCgb() const { return mem_.isCgb(); }
|
|
|
|
- void setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32) {
|
|
+ void setDmgPaletteColor(int palNum, int colorNum, uint_least32_t rgb32) {
|
|
mem_.setDmgPaletteColor(palNum, colorNum, rgb32);
|
|
}
|
|
|
|
void setGameGenie(std::string const &codes) { mem_.setGameGenie(codes); }
|
|
void setGameShark(std::string const &codes) { mem_.setGameShark(codes); }
|
|
|
|
+ void setRtcBase(time_t time) { mem_.setRtcBase(time); }
|
|
+ time_t getRtcBase() { return mem_.getRtcBase(); }
|
|
+ std::pair<unsigned char*, size_t> getWorkRam() { return mem_.getWorkRam(); }
|
|
+ std::pair<unsigned char*, size_t> getSaveRam() { return mem_.getSaveRam(); }
|
|
+ std::pair<unsigned char*, size_t> getIoRam() { return mem_.getIoRam(); }
|
|
+ std::pair<unsigned char*, size_t> getVideoRam() { return mem_.getVideoRam(); };
|
|
+
|
|
private:
|
|
Memory mem_;
|
|
- unsigned long cycleCounter_;
|
|
+ unsigned 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 process(unsigned cycles);
|
|
};
|
|
|
|
}
|
|
diff --git a/libgambatte/src/file/file.cpp b/libgambatte/src/file/file.cpp
|
|
index e6922b2..130e0e2 100644
|
|
--- a/libgambatte/src/file/file.cpp
|
|
+++ b/libgambatte/src/file/file.cpp
|
|
@@ -20,7 +20,41 @@ Free Software Foundation, Inc.,
|
|
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
***************************************************************************/
|
|
#include "stdfile.h"
|
|
+#include <cstring>
|
|
+
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
|
|
transfer_ptr<gambatte::File> gambatte::newFileInstance(std::string const &filepath) {
|
|
return transfer_ptr<File>(new StdFile(filepath.c_str()));
|
|
}
|
|
+
|
|
+namespace
|
|
+{
|
|
+ struct MemoryFile : public gambatte::File
|
|
+ {
|
|
+ MemoryFile(const unsigned char* image, size_t isize) : buf(image), bufsize(isize),
|
|
+ ptr(0), xfail(false) {}
|
|
+ ~MemoryFile() {}
|
|
+ void rewind() { ptr = 0; xfail = false; }
|
|
+ std::size_t size() const { return bufsize; }
|
|
+ void read(char *buffer, std::size_t amount) {
|
|
+ if(amount > bufsize - ptr) {
|
|
+ memcpy(buffer, buf, bufsize - ptr);
|
|
+ xfail = true;
|
|
+ } else
|
|
+ memcpy(buffer, buf, amount);
|
|
+ }
|
|
+ bool fail() const { return xfail; }
|
|
+ private:
|
|
+ const unsigned char* buf;
|
|
+ size_t bufsize;
|
|
+ size_t ptr;
|
|
+ bool xfail;
|
|
+ };
|
|
+}
|
|
+
|
|
+transfer_ptr<gambatte::File> gambatte::newFileInstance(const unsigned char* image, size_t isize) {
|
|
+ return transfer_ptr<File>(new MemoryFile(image, isize));
|
|
+}
|
|
diff --git a/libgambatte/src/file/file.h b/libgambatte/src/file/file.h
|
|
index efde793..ed04461 100644
|
|
--- a/libgambatte/src/file/file.h
|
|
+++ b/libgambatte/src/file/file.h
|
|
@@ -22,6 +22,15 @@ Free Software Foundation, Inc.,
|
|
#ifndef GAMBATTE_FILE_H
|
|
#define GAMBATTE_FILE_H
|
|
|
|
+
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+//
|
|
+// Modified 2012-07-10 by H. Ilari Liusvaara
|
|
+// - New API methods.
|
|
+
|
|
+#include <memory>
|
|
#include "transfer_ptr.h"
|
|
#include <string>
|
|
|
|
@@ -37,6 +46,7 @@ public:
|
|
};
|
|
|
|
transfer_ptr<File> newFileInstance(std::string const &filepath);
|
|
+transfer_ptr<File> newFileInstance(const unsigned char* image, size_t isize);
|
|
|
|
}
|
|
|
|
diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp
|
|
index ffe35b3..0204557 100644
|
|
--- a/libgambatte/src/gambatte.cpp
|
|
+++ b/libgambatte/src/gambatte.cpp
|
|
@@ -25,6 +25,10 @@
|
|
#include <cstring>
|
|
#include <sstream>
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
static std::string const itos(int i) {
|
|
std::stringstream ss;
|
|
ss << i;
|
|
@@ -35,6 +39,14 @@ static std::string const statePath(std::string const &basePath, int stateNo) {
|
|
return basePath + "_" + itos(stateNo) + ".gqs";
|
|
}
|
|
|
|
+namespace
|
|
+{
|
|
+ time_t default_walltime()
|
|
+ {
|
|
+ return time(0);
|
|
+ }
|
|
+}
|
|
+
|
|
namespace gambatte {
|
|
|
|
struct GB::Priv {
|
|
@@ -42,10 +54,10 @@ struct GB::Priv {
|
|
int stateNo;
|
|
unsigned loadflags;
|
|
|
|
- Priv() : stateNo(1), loadflags(0) {}
|
|
+ Priv(time_t (**_getCurrentTime)()) : stateNo(1), loadflags(0), cpu(_getCurrentTime) {}
|
|
};
|
|
|
|
-GB::GB() : p_(new Priv) {}
|
|
+GB::GB() : p_(new Priv(&walltime)), walltime(default_walltime) {}
|
|
|
|
GB::~GB() {
|
|
if (p_->cpu.loaded())
|
|
@@ -54,8 +66,8 @@ GB::~GB() {
|
|
delete p_;
|
|
}
|
|
|
|
-std::ptrdiff_t GB::runFor(gambatte::uint_least32_t *const videoBuf, std::ptrdiff_t const pitch,
|
|
- gambatte::uint_least32_t *const soundBuf, std::size_t &samples) {
|
|
+signed GB::runFor(gambatte::uint_least32_t *const videoBuf, std::ptrdiff_t const pitch,
|
|
+ gambatte::uint_least32_t *const soundBuf, unsigned &samples) {
|
|
if (!p_->cpu.loaded()) {
|
|
samples = 0;
|
|
return -1;
|
|
@@ -64,10 +76,10 @@ std::ptrdiff_t GB::runFor(gambatte::uint_least32_t *const videoBuf, std::ptrdiff
|
|
p_->cpu.setVideoBuffer(videoBuf, pitch);
|
|
p_->cpu.setSoundBuffer(soundBuf);
|
|
|
|
- long const cyclesSinceBlit = p_->cpu.runFor(samples * 2);
|
|
+ signed const cyclesSinceBlit = p_->cpu.runFor(samples * 2);
|
|
samples = p_->cpu.fillSoundBuffer();
|
|
return cyclesSinceBlit >= 0
|
|
- ? static_cast<std::ptrdiff_t>(samples) - (cyclesSinceBlit >> 1)
|
|
+ ? static_cast<signed>(samples) - (cyclesSinceBlit >> 1)
|
|
: cyclesSinceBlit;
|
|
}
|
|
|
|
@@ -77,7 +89,7 @@ void GB::reset() {
|
|
|
|
SaveState state;
|
|
p_->cpu.setStatePtrs(state);
|
|
- setInitState(state, p_->cpu.isCgb(), p_->loadflags & GBA_CGB);
|
|
+ setInitState(state, p_->cpu.isCgb(), p_->loadflags & GBA_CGB, walltime());
|
|
p_->cpu.loadState(state);
|
|
p_->cpu.loadSavedata();
|
|
}
|
|
@@ -91,24 +103,44 @@ void GB::setSaveDir(std::string const &sdir) {
|
|
p_->cpu.setSaveDir(sdir);
|
|
}
|
|
|
|
-LoadRes GB::load(std::string const &romfile, unsigned const flags) {
|
|
+void GB::preload_common()
|
|
+{
|
|
if (p_->cpu.loaded())
|
|
p_->cpu.saveSavedata();
|
|
+}
|
|
+
|
|
+void GB::postload_common(const unsigned flags)
|
|
+{
|
|
+ SaveState state;
|
|
+ p_->cpu.setStatePtrs(state);
|
|
+ setInitState(state, p_->cpu.isCgb(), flags & GBA_CGB, walltime());
|
|
+ p_->cpu.loadState(state);
|
|
+ p_->cpu.loadSavedata();
|
|
+
|
|
+ p_->stateNo = 1;
|
|
+ p_->cpu.setOsdElement(transfer_ptr<OsdElement>());
|
|
+}
|
|
+
|
|
+LoadRes GB::load(std::string const &romfile, unsigned const flags) {
|
|
+ preload_common();
|
|
|
|
LoadRes const loadres = p_->cpu.load(romfile,
|
|
flags & FORCE_DMG,
|
|
flags & MULTICART_COMPAT);
|
|
- if (loadres == LOADRES_OK) {
|
|
- SaveState state;
|
|
- p_->cpu.setStatePtrs(state);
|
|
- p_->loadflags = flags;
|
|
- setInitState(state, p_->cpu.isCgb(), flags & GBA_CGB);
|
|
- p_->cpu.loadState(state);
|
|
- p_->cpu.loadSavedata();
|
|
|
|
- p_->stateNo = 1;
|
|
- p_->cpu.setOsdElement(transfer_ptr<OsdElement>());
|
|
- }
|
|
+ if (loadres == LOADRES_OK)
|
|
+ postload_common(flags);
|
|
+
|
|
+ return loadres;
|
|
+}
|
|
+
|
|
+LoadRes GB::load(const unsigned char* image, size_t isize, unsigned flags) {
|
|
+ preload_common();
|
|
+
|
|
+ LoadRes const loadres = p_->cpu.load(image, isize, flags & FORCE_DMG, flags & MULTICART_COMPAT);
|
|
+
|
|
+ if (loadres == LOADRES_OK)
|
|
+ postload_common(flags);
|
|
|
|
return loadres;
|
|
}
|
|
@@ -126,7 +158,7 @@ void GB::saveSavedata() {
|
|
p_->cpu.saveSavedata();
|
|
}
|
|
|
|
-void GB::setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32) {
|
|
+void GB::setDmgPaletteColor(int palNum, int colorNum, uint_least32_t rgb32) {
|
|
p_->cpu.setDmgPaletteColor(palNum, colorNum, rgb32);
|
|
}
|
|
|
|
@@ -176,6 +208,29 @@ bool GB::saveState(gambatte::uint_least32_t const *videoBuf, std::ptrdiff_t pitc
|
|
return false;
|
|
}
|
|
|
|
+void GB::saveState(std::vector<char>& data, const std::vector<char>& cmpdata) {
|
|
+ if (p_->cpu.loaded()) {
|
|
+ loadsave_save l(cmpdata);
|
|
+ p_->cpu.loadOrSave(l);
|
|
+ data = l.get();
|
|
+ }
|
|
+}
|
|
+
|
|
+void GB::saveState(std::vector<char>& data) {
|
|
+ if (p_->cpu.loaded()) {
|
|
+ loadsave_save l;
|
|
+ p_->cpu.loadOrSave(l);
|
|
+ data = l.get();
|
|
+ }
|
|
+}
|
|
+
|
|
+void GB::loadState(const std::vector<char>& data) {
|
|
+ if (p_->cpu.loaded()) {
|
|
+ loadsave_load l(data);
|
|
+ p_->cpu.loadOrSave(l);
|
|
+ }
|
|
+}
|
|
+
|
|
void GB::selectState(int n) {
|
|
n -= (n / 10) * 10;
|
|
p_->stateNo = n < 0 ? n + 10 : n;
|
|
@@ -209,4 +264,38 @@ void GB::setGameShark(std::string const &codes) {
|
|
p_->cpu.setGameShark(codes);
|
|
}
|
|
|
|
+void GB::setRtcBase(time_t time) {
|
|
+ p_->cpu.setRtcBase(time);
|
|
+}
|
|
+
|
|
+time_t GB::getRtcBase() {
|
|
+ return p_->cpu.getRtcBase();
|
|
+}
|
|
+
|
|
+std::pair<unsigned char*, size_t> GB::getWorkRam() {
|
|
+ return p_->cpu.getWorkRam();
|
|
+}
|
|
+
|
|
+std::pair<unsigned char*, size_t> GB::getSaveRam() {
|
|
+ return p_->cpu.getSaveRam();
|
|
+}
|
|
+
|
|
+std::pair<unsigned char*, size_t> GB::getIoRam() {
|
|
+ return p_->cpu.getIoRam();
|
|
+}
|
|
+
|
|
+std::pair<unsigned char*, size_t> GB::getVideoRam() {
|
|
+ return p_->cpu.getVideoRam();
|
|
+}
|
|
+
|
|
+void GB::set_walltime_fn(time_t (*_walltime)())
|
|
+{
|
|
+ walltime = _walltime;
|
|
+}
|
|
+
|
|
+std::string GB::version()
|
|
+{
|
|
+ return "r537";
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/initstate.cpp b/libgambatte/src/initstate.cpp
|
|
index 2a31f44..496a7d2 100644
|
|
--- a/libgambatte/src/initstate.cpp
|
|
+++ b/libgambatte/src/initstate.cpp
|
|
@@ -24,6 +24,10 @@
|
|
#include <cstring>
|
|
#include <ctime>
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace {
|
|
|
|
static void setInitialCgbWram(unsigned char *const wram) {
|
|
@@ -1147,7 +1151,7 @@ static void setInitialDmgIoamhram(unsigned char *const ioamhram) {
|
|
|
|
} // anon namespace
|
|
|
|
-void gambatte::setInitState(SaveState &state, bool const cgb, bool const gbaCgbMode) {
|
|
+void gambatte::setInitState(SaveState &state, bool const cgb, bool const gbaCgbMode, time_t starttime) {
|
|
static unsigned char const cgbObjpDump[0x40] = {
|
|
0x00, 0x00, 0xF2, 0xAB,
|
|
0x61, 0xC2, 0xD9, 0xBA,
|
|
@@ -1310,7 +1314,7 @@ void gambatte::setInitState(SaveState &state, bool const cgb, bool const gbaCgbM
|
|
state.spu.ch4.nr4 = 0;
|
|
state.spu.ch4.master = false;
|
|
|
|
- state.rtc.baseTime = std::time(0);
|
|
+ state.rtc.baseTime = starttime;
|
|
state.rtc.haltTime = state.rtc.baseTime;
|
|
state.rtc.dataDh = 0;
|
|
state.rtc.dataDl = 0;
|
|
diff --git a/libgambatte/src/initstate.h b/libgambatte/src/initstate.h
|
|
index bdb33dd..f4d4a02 100644
|
|
--- a/libgambatte/src/initstate.h
|
|
+++ b/libgambatte/src/initstate.h
|
|
@@ -19,9 +19,15 @@
|
|
#ifndef INITSTATE_H
|
|
#define INITSTATE_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
+#include <ctime>
|
|
+
|
|
namespace gambatte {
|
|
|
|
-void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode);
|
|
+void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode, time_t starttime);
|
|
|
|
}
|
|
|
|
diff --git a/libgambatte/src/interrupter.cpp b/libgambatte/src/interrupter.cpp
|
|
index ac958f9..f0770a8 100644
|
|
--- a/libgambatte/src/interrupter.cpp
|
|
+++ b/libgambatte/src/interrupter.cpp
|
|
@@ -19,6 +19,10 @@
|
|
#include "interrupter.h"
|
|
#include "memory.h"
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
Interrupter::Interrupter(unsigned short &sp, unsigned short &pc)
|
|
@@ -27,7 +31,7 @@ Interrupter::Interrupter(unsigned short &sp, unsigned short &pc)
|
|
{
|
|
}
|
|
|
|
-unsigned long Interrupter::interrupt(unsigned const address, unsigned long cc, Memory &memory) {
|
|
+unsigned Interrupter::interrupt(unsigned const address, unsigned cc, Memory &memory) {
|
|
cc += 8;
|
|
sp_ = (sp_ - 1) & 0xFFFF;
|
|
memory.write(sp_, pc_ >> 8, cc);
|
|
@@ -66,11 +70,20 @@ void Interrupter::setGameShark(std::string const &codes) {
|
|
}
|
|
}
|
|
|
|
-void Interrupter::applyVblankCheats(unsigned long const cc, Memory &memory) {
|
|
+void Interrupter::applyVblankCheats(unsigned const cc, Memory &memory) {
|
|
for (std::size_t i = 0, size = gsCodes_.size(); i < size; ++i) {
|
|
if (gsCodes_[i].type == 0x01)
|
|
memory.write(gsCodes_[i].address, gsCodes_[i].value, cc);
|
|
}
|
|
}
|
|
|
|
+void Interrupter::loadOrSave(loadsave& state) {
|
|
+ unsigned gssize = gsCodes_.size();
|
|
+ state(gssize);
|
|
+ if(!state.saving())
|
|
+ gsCodes_.resize(gssize);
|
|
+ for(unsigned i = 0; i < gssize; i++)
|
|
+ gsCodes_[i].loadOrSave(state);
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/interrupter.h b/libgambatte/src/interrupter.h
|
|
index fa7314d..328f7a8 100644
|
|
--- a/libgambatte/src/interrupter.h
|
|
+++ b/libgambatte/src/interrupter.h
|
|
@@ -19,8 +19,14 @@
|
|
#ifndef INTERRUPTER_H
|
|
#define INTERRUPTER_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include <string>
|
|
#include <vector>
|
|
+#include "loadsave.h"
|
|
+
|
|
|
|
namespace gambatte {
|
|
|
|
@@ -28,6 +34,12 @@ struct GsCode {
|
|
unsigned short address;
|
|
unsigned char value;
|
|
unsigned char type;
|
|
+
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ state(address);
|
|
+ state(value);
|
|
+ state(type);
|
|
+ }
|
|
};
|
|
|
|
class Memory;
|
|
@@ -35,15 +47,16 @@ class Memory;
|
|
class Interrupter {
|
|
public:
|
|
Interrupter(unsigned short &sp, unsigned short &pc);
|
|
- unsigned long interrupt(unsigned address, unsigned long cycleCounter, Memory &memory);
|
|
+ unsigned interrupt(unsigned address, unsigned cycleCounter, Memory &memory);
|
|
void setGameShark(std::string const &codes);
|
|
+ void loadOrSave(loadsave& state);
|
|
|
|
private:
|
|
unsigned short &sp_;
|
|
unsigned short &pc_;
|
|
std::vector<GsCode> gsCodes_;
|
|
|
|
- void applyVblankCheats(unsigned long cc, Memory &mem);
|
|
+ void applyVblankCheats(unsigned cc, Memory &mem);
|
|
};
|
|
|
|
}
|
|
diff --git a/libgambatte/src/interruptrequester.cpp b/libgambatte/src/interruptrequester.cpp
|
|
index 400733e..5091a81 100644
|
|
--- a/libgambatte/src/interruptrequester.cpp
|
|
+++ b/libgambatte/src/interruptrequester.cpp
|
|
@@ -19,6 +19,10 @@
|
|
#include "interruptrequester.h"
|
|
#include "savestate.h"
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
InterruptRequester::InterruptRequester()
|
|
@@ -34,6 +38,15 @@ void InterruptRequester::saveState(SaveState &state) const {
|
|
state.mem.halted = halted();
|
|
}
|
|
|
|
+void InterruptRequester::loadOrSave(loadsave& state)
|
|
+{
|
|
+ eventTimes_.loadOrSave(state);
|
|
+ state(minIntTime_);
|
|
+ state(ifreg_);
|
|
+ state(iereg_);
|
|
+ intFlags_.loadOrSave(state);
|
|
+}
|
|
+
|
|
void InterruptRequester::loadState(SaveState const &state) {
|
|
minIntTime_ = state.mem.minIntTime;
|
|
ifreg_ = state.mem.ioamhram.get()[0x10F];
|
|
@@ -42,17 +55,17 @@ void InterruptRequester::loadState(SaveState const &state) {
|
|
|
|
eventTimes_.setValue<intevent_interrupts>(intFlags_.imeOrHalted() && pendingIrqs()
|
|
? minIntTime_
|
|
- : static_cast<unsigned long>(disabled_time));
|
|
+ : static_cast<unsigned>(disabled_time));
|
|
}
|
|
|
|
-void InterruptRequester::resetCc(unsigned long oldCc, unsigned long newCc) {
|
|
+void InterruptRequester::resetCc(unsigned oldCc, unsigned newCc) {
|
|
minIntTime_ = minIntTime_ < oldCc ? 0 : minIntTime_ - (oldCc - newCc);
|
|
|
|
if (eventTimes_.value(intevent_interrupts) != disabled_time)
|
|
eventTimes_.setValue<intevent_interrupts>(minIntTime_);
|
|
}
|
|
|
|
-void InterruptRequester::ei(unsigned long cc) {
|
|
+void InterruptRequester::ei(unsigned cc) {
|
|
intFlags_.setIme();
|
|
minIntTime_ = cc + 1;
|
|
|
|
@@ -99,7 +112,7 @@ void InterruptRequester::setIereg(unsigned iereg) {
|
|
if (intFlags_.imeOrHalted()) {
|
|
eventTimes_.setValue<intevent_interrupts>(pendingIrqs()
|
|
? minIntTime_
|
|
- : static_cast<unsigned long>(disabled_time));
|
|
+ : static_cast<unsigned>(disabled_time));
|
|
}
|
|
}
|
|
|
|
@@ -109,7 +122,7 @@ void InterruptRequester::setIfreg(unsigned ifreg) {
|
|
if (intFlags_.imeOrHalted()) {
|
|
eventTimes_.setValue<intevent_interrupts>(pendingIrqs()
|
|
? minIntTime_
|
|
- : static_cast<unsigned long>(disabled_time));
|
|
+ : static_cast<unsigned>(disabled_time));
|
|
}
|
|
}
|
|
|
|
diff --git a/libgambatte/src/interruptrequester.h b/libgambatte/src/interruptrequester.h
|
|
index 24da184..0d423dc 100644
|
|
--- a/libgambatte/src/interruptrequester.h
|
|
+++ b/libgambatte/src/interruptrequester.h
|
|
@@ -19,11 +19,17 @@
|
|
#ifndef INTERRUPT_REQUESTER_H
|
|
#define INTERRUPT_REQUESTER_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include "counterdef.h"
|
|
#include "minkeeper.h"
|
|
+#include "loadsave.h"
|
|
|
|
namespace gambatte {
|
|
|
|
+
|
|
struct SaveState;
|
|
|
|
enum IntEventId { intevent_unhalt,
|
|
@@ -41,12 +47,12 @@ public:
|
|
InterruptRequester();
|
|
void saveState(SaveState &) const;
|
|
void loadState(SaveState const &);
|
|
- void resetCc(unsigned long oldCc, unsigned long newCc);
|
|
+ void resetCc(unsigned oldCc, unsigned newCc);
|
|
unsigned ifreg() const { return ifreg_; }
|
|
unsigned pendingIrqs() const { return ifreg_ & iereg_; }
|
|
bool ime() const { return intFlags_.ime(); }
|
|
bool halted() const { return intFlags_.halted(); }
|
|
- void ei(unsigned long cc);
|
|
+ void ei(unsigned cc);
|
|
void di();
|
|
void halt();
|
|
void unhalt();
|
|
@@ -54,12 +60,13 @@ public:
|
|
void ackIrq(unsigned bit);
|
|
void setIereg(unsigned iereg);
|
|
void setIfreg(unsigned ifreg);
|
|
+ void loadOrSave(loadsave& state);
|
|
|
|
IntEventId minEventId() const { return static_cast<IntEventId>(eventTimes_.min()); }
|
|
- unsigned long minEventTime() const { return eventTimes_.minValue(); }
|
|
- template<IntEventId id> void setEventTime(unsigned long value) { eventTimes_.setValue<id>(value); }
|
|
- void setEventTime(IntEventId id, unsigned long value) { eventTimes_.setValue(id, value); }
|
|
- unsigned long eventTime(IntEventId id) const { return eventTimes_.value(id); }
|
|
+ unsigned minEventTime() const { return eventTimes_.minValue(); }
|
|
+ template<IntEventId id> void setEventTime(unsigned value) { eventTimes_.setValue<id>(value); }
|
|
+ void setEventTime(IntEventId id, unsigned value) { eventTimes_.setValue(id, value); }
|
|
+ unsigned eventTime(IntEventId id) const { return eventTimes_.value(id); }
|
|
|
|
private:
|
|
class IntFlags {
|
|
@@ -74,13 +81,15 @@ private:
|
|
void unsetHalted() { flags_ &= ~flag_halted; }
|
|
void set(bool ime, bool halted) { flags_ = halted * flag_halted + ime * flag_ime; }
|
|
|
|
+ void loadOrSave(loadsave& state) { state(flags_); }
|
|
+
|
|
private:
|
|
unsigned char flags_;
|
|
enum { flag_ime = 1, flag_halted = 2 };
|
|
};
|
|
|
|
MinKeeper<intevent_last + 1> eventTimes_;
|
|
- unsigned long minIntTime_;
|
|
+ unsigned minIntTime_;
|
|
unsigned ifreg_;
|
|
unsigned iereg_;
|
|
IntFlags intFlags_;
|
|
diff --git a/libgambatte/src/loadsave.cpp b/libgambatte/src/loadsave.cpp
|
|
new file mode 100644
|
|
index 0000000..37ea71a
|
|
--- /dev/null
|
|
+++ b/libgambatte/src/loadsave.cpp
|
|
@@ -0,0 +1,266 @@
|
|
+/***************************************************************************
|
|
+ * Copyright (C) 2012 by H. Ilari Liusvaara *
|
|
+ * ilari.liusvaara@elisanet.fi *
|
|
+ * *
|
|
+ * 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 "loadsave.h"
|
|
+#include <stdexcept>
|
|
+#include <cstring>
|
|
+#include <iostream>
|
|
+
|
|
+namespace gambatte {
|
|
+
|
|
+loadsave::~loadsave() throw() {}
|
|
+
|
|
+loadsave_load::loadsave_load(const std::vector<char>& _memory)
|
|
+ : memory(_memory)
|
|
+{
|
|
+ ptr = 0;
|
|
+}
|
|
+
|
|
+template<typename T> void loadsave_load::do_op(T& x)
|
|
+{
|
|
+ unsigned long long v = 0;
|
|
+ if(ptr + sizeof(T) > memory.size())
|
|
+ throw std::runtime_error("Loadstate overflow");
|
|
+ for(size_t i = 0; i < sizeof(T); i++)
|
|
+ v |= ((unsigned long long)(unsigned char)memory[ptr++] << (8 * (sizeof(T) - i - 1)));
|
|
+ x = (T)v;
|
|
+}
|
|
+
|
|
+template<typename T> void loadsave_load::do_op(T& x, unsigned char _tag)
|
|
+{
|
|
+ if(ptr + 1 > memory.size())
|
|
+ throw std::runtime_error("Loadstate overflow");
|
|
+ unsigned char _rtag = memory[ptr++];
|
|
+ if(_rtag != _tag) {
|
|
+ std::cerr << "Wrong type tag: expected=" << (int)_tag << ", got=" << (int)_rtag << std::endl;
|
|
+ throw std::runtime_error("Loadstate desynced");
|
|
+ }
|
|
+ do_op(x);
|
|
+}
|
|
+
|
|
+template<typename T> void loadsave_load::do_op(T* x, size_t s, unsigned char _tag)
|
|
+{
|
|
+ if(ptr + 1 > memory.size())
|
|
+ throw std::runtime_error("Loadstate overflow");
|
|
+ unsigned char _rtag = memory[ptr++];
|
|
+ if(_rtag != _tag) {
|
|
+ std::cerr << "Wrong type tag: expected=" << (int)_tag << ", got=" << (int)_rtag << std::endl;
|
|
+ throw std::runtime_error("Loadstate desynced");
|
|
+ }
|
|
+ unsigned size;
|
|
+ do_op(size);
|
|
+ if(size != s) {
|
|
+ std::cerr << "Wrong number of entries: expected=" << s << ", got=" << size << std::endl;
|
|
+ throw std::runtime_error("Loadstate desynced");
|
|
+ }
|
|
+ for(size_t i = 0; i < s; i++)
|
|
+ do_op(x[i]);
|
|
+}
|
|
+
|
|
+void loadsave_load::operator()(bool& x)
|
|
+{
|
|
+ char c;
|
|
+ do_op(c, 0);
|
|
+ x = (c != 0);
|
|
+}
|
|
+
|
|
+
|
|
+loadsave_load::~loadsave_load() throw() {}
|
|
+void loadsave_load::operator()(signed char& x) { do_op(x, 1); }
|
|
+void loadsave_load::operator()(unsigned char& x) { do_op(x, 2); }
|
|
+void loadsave_load::operator()(signed short& x) { do_op(x, 3); }
|
|
+void loadsave_load::operator()(unsigned short& x) { do_op(x, 4); }
|
|
+void loadsave_load::operator()(signed int& x) { do_op(x, 5); }
|
|
+void loadsave_load::operator()(unsigned int& x) { do_op(x, 6); }
|
|
+void loadsave_load::operator()(signed long long& x) { do_op(x, 7); }
|
|
+void loadsave_load::operator()(unsigned long long& x) { do_op(x, 8); }
|
|
+void loadsave_load::operator()(signed char* x, size_t s) { do_op(x, s, 9); }
|
|
+void loadsave_load::operator()(unsigned char* x, size_t s) { do_op(x, s, 10); }
|
|
+void loadsave_load::operator()(signed short* x, size_t s) { do_op(x, s, 11); }
|
|
+void loadsave_load::operator()(unsigned short* x, size_t s) { do_op(x, s, 12); }
|
|
+void loadsave_load::operator()(signed int* x, size_t s) { do_op(x, s, 13); }
|
|
+void loadsave_load::operator()(unsigned int* x, size_t s) { do_op(x, s, 14); }
|
|
+void loadsave_load::operator()(signed long long* x, size_t s) { do_op(x, s, 15); }
|
|
+void loadsave_load::operator()(unsigned long long* x, size_t s) { do_op(x, s, 16); }
|
|
+
|
|
+void loadsave_load::tag(unsigned short _tag)
|
|
+{
|
|
+ unsigned short _rtag;
|
|
+ do_op(_rtag, 18);
|
|
+ if(_tag != _rtag) {
|
|
+ std::cerr << "Wrong inner tag: expected=" << (int)_tag << ", got=" << (int)_rtag << std::endl;
|
|
+ throw std::runtime_error("Loadstate desynced");
|
|
+ }
|
|
+}
|
|
+
|
|
+void loadsave_load::operator()(unsigned char*& ptr, unsigned char* abase)
|
|
+{
|
|
+ char x;
|
|
+ do_op(x, 17);
|
|
+ if(!x)
|
|
+ ptr = NULL;
|
|
+ else {
|
|
+ unsigned y;
|
|
+ do_op(y);
|
|
+ ptr = abase + y;
|
|
+ }
|
|
+}
|
|
+
|
|
+void loadsave_load::operator()(const unsigned char*& ptr, unsigned char* abase)
|
|
+{
|
|
+ char x;
|
|
+ do_op(x, 19);
|
|
+ if(!x)
|
|
+ ptr = NULL;
|
|
+ else {
|
|
+ unsigned y;
|
|
+ do_op(y);
|
|
+ ptr = abase + y;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+bool loadsave_load::saving() { return false; }
|
|
+
|
|
+#define BLOCKBYTES 65500
|
|
+
|
|
+void loadsave_save::pushbytes(char* bytes, size_t amount)
|
|
+{
|
|
+ if(!nextptr || memory[nextptr - 1].second + amount > BLOCKBYTES) {
|
|
+ memory.push_back(std::make_pair(new char[BLOCKBYTES], (size_t)0));
|
|
+ nextptr++;
|
|
+ }
|
|
+ if(cmp.size())
|
|
+ try { if(cmp.size() < used + amount || memcmp(&cmp[used], bytes, amount)) throw 42; } catch(...) {}
|
|
+ memcpy(memory[nextptr - 1].first + memory[nextptr - 1].second, bytes, amount);
|
|
+ memory[nextptr - 1].second += amount;
|
|
+ used += amount;
|
|
+}
|
|
+
|
|
+template<typename T> void loadsave_save::do_op(T& x)
|
|
+{
|
|
+ unsigned long long v = x;
|
|
+ char buf[sizeof(T)];
|
|
+ for(size_t i = 0; i < sizeof(T); i++)
|
|
+ buf[i] = v >> (8 * (sizeof(T) - i - 1));
|
|
+ pushbytes(buf, sizeof(T));
|
|
+}
|
|
+
|
|
+template<typename T> void loadsave_save::do_op(T& x, unsigned char _tag)
|
|
+{
|
|
+ pushbytes((char*)&_tag, 1);
|
|
+ do_op(x);
|
|
+}
|
|
+
|
|
+template<typename T> void loadsave_save::do_op(T* x, size_t s, unsigned char _tag)
|
|
+{
|
|
+ pushbytes((char*)&_tag, 1);
|
|
+ unsigned size = s;
|
|
+ do_op(size);
|
|
+ for(size_t i = 0; i < s; i++)
|
|
+ do_op(x[i]);
|
|
+}
|
|
+
|
|
+loadsave_save::loadsave_save()
|
|
+{
|
|
+ used = 0;
|
|
+ nextptr = 0;
|
|
+}
|
|
+
|
|
+loadsave_save::loadsave_save(const std::vector<char>& _memory)
|
|
+{
|
|
+ used = 0;
|
|
+ nextptr = 0;
|
|
+ cmp = _memory;
|
|
+}
|
|
+
|
|
+loadsave_save::~loadsave_save() throw()
|
|
+{
|
|
+ for(auto i : memory)
|
|
+ delete[] i.first;
|
|
+}
|
|
+
|
|
+void loadsave_save::operator()(bool& x)
|
|
+{
|
|
+ char y = x ? 1 : 0;
|
|
+ char z = 0;
|
|
+ pushbytes(&z, 1);
|
|
+ pushbytes(&y, 1);
|
|
+}
|
|
+
|
|
+void loadsave_save::operator()(signed char& x) { do_op(x, 1); }
|
|
+void loadsave_save::operator()(unsigned char& x) { do_op(x, 2); }
|
|
+void loadsave_save::operator()(signed short& x) { do_op(x, 3); }
|
|
+void loadsave_save::operator()(unsigned short& x) { do_op(x, 4); }
|
|
+void loadsave_save::operator()(signed int& x) { do_op(x, 5); }
|
|
+void loadsave_save::operator()(unsigned int& x) { do_op(x, 6); }
|
|
+void loadsave_save::operator()(signed long long& x) { do_op(x, 7); }
|
|
+void loadsave_save::operator()(unsigned long long& x) { do_op(x, 8); }
|
|
+void loadsave_save::operator()(signed char* x, size_t s) { do_op(x, s, 9); }
|
|
+void loadsave_save::operator()(unsigned char* x, size_t s) { do_op(x, s, 10); }
|
|
+void loadsave_save::operator()(signed short* x, size_t s) { do_op(x, s, 11); }
|
|
+void loadsave_save::operator()(unsigned short* x, size_t s) { do_op(x, s, 12); }
|
|
+void loadsave_save::operator()(signed int* x, size_t s) { do_op(x, s, 13); }
|
|
+void loadsave_save::operator()(unsigned int* x, size_t s) { do_op(x, s, 14); }
|
|
+void loadsave_save::operator()(signed long long* x, size_t s) { do_op(x, s, 15); }
|
|
+void loadsave_save::operator()(unsigned long long* x, size_t s) { do_op(x, s, 16); }
|
|
+bool loadsave_save::saving() { return true; }
|
|
+
|
|
+void loadsave_save::operator()(unsigned char*& ptr, unsigned char* abase)
|
|
+{
|
|
+ if(!ptr) {
|
|
+ char x = 0;
|
|
+ do_op(x, 17);
|
|
+ } else {
|
|
+ char x = 1;
|
|
+ unsigned y = ptr - abase;
|
|
+ do_op(x, 17);
|
|
+ do_op(y);
|
|
+ }
|
|
+}
|
|
+
|
|
+void loadsave_save::operator()(const unsigned char*& ptr, unsigned char* abase)
|
|
+{
|
|
+ if(!ptr) {
|
|
+ char x = 0;
|
|
+ do_op(x, 19);
|
|
+ } else {
|
|
+ char x = 1;
|
|
+ unsigned y = ptr - abase;
|
|
+ do_op(x, 19);
|
|
+ do_op(y);
|
|
+ }
|
|
+}
|
|
+
|
|
+void loadsave_save::tag(unsigned short _tag)
|
|
+{
|
|
+ do_op(_tag, 18);
|
|
+}
|
|
+
|
|
+std::vector<char> loadsave_save::get()
|
|
+{
|
|
+ std::vector<char> x;
|
|
+ x.resize(used);
|
|
+ size_t ptr = 0;
|
|
+ for(auto i : memory) {
|
|
+ memcpy(&x[ptr], i.first, i.second);
|
|
+ ptr += i.second;
|
|
+ }
|
|
+ return x;
|
|
+}
|
|
+}
|
|
diff --git a/libgambatte/src/loadsave.h b/libgambatte/src/loadsave.h
|
|
new file mode 100644
|
|
index 0000000..10ebf63
|
|
--- /dev/null
|
|
+++ b/libgambatte/src/loadsave.h
|
|
@@ -0,0 +1,160 @@
|
|
+#ifndef _loadsave__hpp__included__
|
|
+#define _loadsave__hpp__included__
|
|
+/***************************************************************************
|
|
+ * Copyright (C) 2012 by H. Ilari Liusvaara *
|
|
+ * ilari.liusvaara@elisanet.fi *
|
|
+ * *
|
|
+ * 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 <cstdint>
|
|
+#include <vector>
|
|
+#include <cstdlib>
|
|
+#include <stdexcept>
|
|
+
|
|
+namespace gambatte {
|
|
+ class loadsave
|
|
+ {
|
|
+ private:
|
|
+ unsigned enumVal;
|
|
+ bool enumAssigned;
|
|
+ public:
|
|
+ virtual ~loadsave() throw();
|
|
+ virtual void operator()(bool& x) = 0;
|
|
+ virtual void operator()(signed char& x) = 0;
|
|
+ virtual void operator()(unsigned char& x) = 0;
|
|
+ virtual void operator()(signed short& x) = 0;
|
|
+ virtual void operator()(unsigned short& x) = 0;
|
|
+ virtual void operator()(signed int& x) = 0;
|
|
+ virtual void operator()(unsigned int& x) = 0;
|
|
+ virtual void operator()(signed long long& x) = 0;
|
|
+ virtual void operator()(unsigned long long& x) = 0;
|
|
+ virtual void operator()(signed char* x, size_t s) = 0;
|
|
+ virtual void operator()(unsigned char* x, size_t s) = 0;
|
|
+ virtual void operator()(signed short* x, size_t s) = 0;
|
|
+ virtual void operator()(unsigned short* x, size_t s) = 0;
|
|
+ virtual void operator()(signed int* x, size_t s) = 0;
|
|
+ virtual void operator()(unsigned int* x, size_t s) = 0;
|
|
+ virtual void operator()(long long* x, size_t s) = 0;
|
|
+ virtual void operator()(unsigned long long* x, size_t s) = 0;
|
|
+ virtual void operator()(unsigned char*& ptr, unsigned char* abase) = 0;
|
|
+ virtual void operator()(const unsigned char*& ptr, unsigned char* abase) = 0;
|
|
+ virtual void tag(unsigned short tag) = 0;
|
|
+ void time(time_t& t) {
|
|
+ unsigned long long t_ = t;
|
|
+ (*this)(t_);
|
|
+ t = t_;
|
|
+ }
|
|
+ void startEnumeration() {
|
|
+ enumAssigned = false;
|
|
+ enumVal = 0xFFFFFFFFU;
|
|
+ if(!saving())
|
|
+ (*this)(enumVal);
|
|
+ }
|
|
+ template<typename T> void enumerate(T& ptr, T candiate, unsigned symbol) {
|
|
+ if(saving()) {
|
|
+ if(ptr == candiate) {
|
|
+ enumVal = symbol;
|
|
+ enumAssigned = true;
|
|
+ }
|
|
+ } else {
|
|
+ if(enumVal == symbol) {
|
|
+ ptr = candiate;
|
|
+ enumAssigned = true;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ void endEnumeration() {
|
|
+ if(saving())
|
|
+ (*this)(enumVal);
|
|
+ if(!enumAssigned)
|
|
+ throw std::runtime_error("Enumeration missing a choice");
|
|
+ }
|
|
+ virtual bool saving() = 0;
|
|
+ };
|
|
+
|
|
+ class loadsave_load : public loadsave
|
|
+ {
|
|
+ const std::vector<char>& memory;
|
|
+ size_t ptr;
|
|
+ template<typename T> inline void do_op(T& x);
|
|
+ template<typename T> inline void do_op(T& x, unsigned char _tag);
|
|
+ template<typename T> void do_op(T* x, size_t s, unsigned char _tag);
|
|
+ public:
|
|
+ loadsave_load(const std::vector<char>& _memory);
|
|
+ ~loadsave_load() throw();
|
|
+ void operator()(bool& x);
|
|
+ void operator()(signed char& x);
|
|
+ void operator()(unsigned char& x);
|
|
+ void operator()(signed short& x);
|
|
+ void operator()(unsigned short& x);
|
|
+ void operator()(signed int& x);
|
|
+ void operator()(unsigned int& x);
|
|
+ void operator()(signed long long& x);
|
|
+ void operator()(unsigned long long& x);
|
|
+ void operator()(signed char* x, size_t s);
|
|
+ void operator()(unsigned char* x, size_t s);
|
|
+ void operator()(signed short* x, size_t s);
|
|
+ void operator()(unsigned short* x, size_t s);
|
|
+ void operator()(signed int* x, size_t s);
|
|
+ void operator()(unsigned int* x, size_t s);
|
|
+ void operator()(signed long long* x, size_t s);
|
|
+ void operator()(unsigned long long* x, size_t s);
|
|
+ void operator()(unsigned char*& ptr, unsigned char* abase);
|
|
+ void operator()(const unsigned char*& ptr, unsigned char* abase);
|
|
+ void tag(unsigned short _tag);
|
|
+ bool saving();
|
|
+ };
|
|
+
|
|
+ class loadsave_save : public loadsave
|
|
+ {
|
|
+ std::vector<std::pair<char*, size_t>> memory;
|
|
+ size_t nextptr;
|
|
+ size_t used;
|
|
+ inline void pushbytes(char* bytes, size_t amount);
|
|
+ template<typename T> inline void do_op(T& x);
|
|
+ template<typename T> inline void do_op(T& x, unsigned char _tag);
|
|
+ template<typename T> void do_op(T* x, size_t s, unsigned char _tag);
|
|
+ std::vector<char> cmp;
|
|
+ public:
|
|
+ loadsave_save();
|
|
+ loadsave_save(const std::vector<char>& _memory);
|
|
+ ~loadsave_save() throw();
|
|
+ void operator()(bool& x);
|
|
+ void operator()(signed char& x);
|
|
+ void operator()(unsigned char& x);
|
|
+ void operator()(signed short& x);
|
|
+ void operator()(unsigned short& x);
|
|
+ void operator()(signed int& x);
|
|
+ void operator()(unsigned int& x);
|
|
+ void operator()(signed long long& x);
|
|
+ void operator()(unsigned long long& x);
|
|
+ void operator()(signed char* x, size_t s);
|
|
+ void operator()(unsigned char* x, size_t s);
|
|
+ void operator()(signed short* x, size_t s);
|
|
+ void operator()(unsigned short* x, size_t s);
|
|
+ void operator()(signed int* x, size_t s);
|
|
+ void operator()(unsigned int* x, size_t s);
|
|
+ void operator()(signed long long* x, size_t s);
|
|
+ void operator()(unsigned long long* x, size_t s);
|
|
+ void operator()(unsigned char*& ptr, unsigned char* abase);
|
|
+ void operator()(const unsigned char*& ptr, unsigned char* abase);
|
|
+ void tag(unsigned short _tag);
|
|
+ bool saving();
|
|
+ std::vector<char> get();
|
|
+ };
|
|
+}
|
|
+
|
|
+#endif
|
|
diff --git a/libgambatte/src/mem/cartridge.cpp b/libgambatte/src/mem/cartridge.cpp
|
|
index 75629f6..d593dc5 100644
|
|
--- a/libgambatte/src/mem/cartridge.cpp
|
|
+++ b/libgambatte/src/mem/cartridge.cpp
|
|
@@ -23,6 +23,10 @@
|
|
#include <cstring>
|
|
#include <fstream>
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
namespace {
|
|
@@ -36,6 +40,8 @@ public:
|
|
virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const {
|
|
return (addr< 0x4000) == (bank == 0);
|
|
}
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ }
|
|
};
|
|
|
|
class Mbc0 : public DefaultMbc {
|
|
@@ -61,6 +67,9 @@ public:
|
|
enableRam_ = ss.enableRam;
|
|
memptrs_.setRambank(enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : 0, 0);
|
|
}
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ state(enableRam_);
|
|
+ }
|
|
|
|
private:
|
|
MemPtrs &memptrs_;
|
|
@@ -130,6 +139,12 @@ public:
|
|
setRombank();
|
|
}
|
|
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ state(rombank_);
|
|
+ state(rambank_);
|
|
+ state(enableRam_);
|
|
+ state(rambankMode_);
|
|
+ }
|
|
private:
|
|
MemPtrs &memptrs_;
|
|
unsigned char rombank_;
|
|
@@ -197,6 +212,11 @@ public:
|
|
virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const {
|
|
return (addr < 0x4000) == ((bank & 0xF) == 0);
|
|
}
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ state(rombank_);
|
|
+ state(enableRam_);
|
|
+ state(rombank0Mode_);
|
|
+ }
|
|
|
|
private:
|
|
MemPtrs &memptrs_;
|
|
@@ -251,6 +271,10 @@ public:
|
|
memptrs_.setRambank(enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : 0, 0);
|
|
memptrs_.setRombank(rombank_ & (rombanks(memptrs_) - 1));
|
|
}
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ state(rombank_);
|
|
+ state(enableRam_);
|
|
+ }
|
|
|
|
private:
|
|
MemPtrs &memptrs_;
|
|
@@ -304,7 +328,12 @@ public:
|
|
setRambank();
|
|
memptrs_.setRombank(rombank_ & (rombanks(memptrs_) - 1));
|
|
}
|
|
-
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ rtc_->loadOrSave(state);
|
|
+ state(rombank_);
|
|
+ state(rambank_);
|
|
+ state(enableRam_);
|
|
+ }
|
|
private:
|
|
MemPtrs &memptrs_;
|
|
Rtc *const rtc_;
|
|
@@ -374,7 +403,12 @@ public:
|
|
setRambank();
|
|
setRombank();
|
|
}
|
|
-
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ state(rombank_);
|
|
+ state(rambank_);
|
|
+ state(enableRam_);
|
|
+ state(rambankMode_);
|
|
+ }
|
|
private:
|
|
MemPtrs &memptrs_;
|
|
unsigned char rombank_;
|
|
@@ -437,6 +471,11 @@ public:
|
|
setRambank();
|
|
setRombank();
|
|
}
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ state(rombank_);
|
|
+ state(rambank_);
|
|
+ state(enableRam_);
|
|
+ }
|
|
|
|
private:
|
|
MemPtrs &memptrs_;
|
|
@@ -536,6 +575,15 @@ LoadRes Cartridge::loadROM(std::string const &romfile,
|
|
bool const multicartCompat)
|
|
{
|
|
scoped_ptr<File> const rom(newFileInstance(romfile));
|
|
+ return loadROM(rom.get(), forceDmg, multicartCompat, romfile);
|
|
+}
|
|
+
|
|
+LoadRes Cartridge::loadROM(const unsigned char* image, size_t isize, const bool forceDmg, const bool multicartCompat) {
|
|
+ const scoped_ptr<File> rom(newFileInstance(image, isize));
|
|
+ return loadROM(rom.get(), forceDmg, multicartCompat, "");
|
|
+}
|
|
+
|
|
+LoadRes Cartridge::loadROM(File* rom, const bool forceDmg, const bool multicartCompat, const std::string& filename) {
|
|
if (rom->fail())
|
|
return LOADRES_IO_ERROR;
|
|
|
|
@@ -626,7 +674,14 @@ LoadRes Cartridge::loadROM(std::string const &romfile,
|
|
if (rom->fail())
|
|
return LOADRES_IO_ERROR;
|
|
|
|
- defaultSaveBasePath_ = stripExtension(romfile);
|
|
+ if(filename != "") {
|
|
+ defaultSaveBasePath_ = stripExtension(filename);
|
|
+ memoryCartridge = false;
|
|
+ } else {
|
|
+ defaultSaveBasePath_ = "";
|
|
+ memoryCartridge = true;
|
|
+ }
|
|
+ clearMemorySavedData();
|
|
|
|
switch (type) {
|
|
case type_plain: mbc_.reset(new Mbc0(memptrs_)); break;
|
|
@@ -667,43 +722,67 @@ void Cartridge::loadSavedata() {
|
|
std::string const &sbp = saveBasePath();
|
|
|
|
if (hasBattery(memptrs_.romdata()[0x147])) {
|
|
- std::ifstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::in);
|
|
+ if(memoryCartridge) {
|
|
+ if(memoryCartridgeSram.size())
|
|
+ memcpy(memptrs_.rambankdata(), &memoryCartridgeSram[0], memptrs_.rambankdataend() - memptrs_.rambankdata());
|
|
+ } else {
|
|
+ std::ifstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::in);
|
|
|
|
- if (file.is_open()) {
|
|
- file.read(reinterpret_cast<char*>(memptrs_.rambankdata()),
|
|
- memptrs_.rambankdataend() - memptrs_.rambankdata());
|
|
- enforce8bit(memptrs_.rambankdata(), memptrs_.rambankdataend() - memptrs_.rambankdata());
|
|
+ if (file.is_open()) {
|
|
+ file.read(reinterpret_cast<char*>(memptrs_.rambankdata()),
|
|
+ memptrs_.rambankdataend() - memptrs_.rambankdata());
|
|
+ enforce8bit(memptrs_.rambankdata(), memptrs_.rambankdataend() - memptrs_.rambankdata());
|
|
+ }
|
|
}
|
|
}
|
|
|
|
if (hasRtc(memptrs_.romdata()[0x147])) {
|
|
- std::ifstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::in);
|
|
- if (file) {
|
|
- unsigned long basetime = file.get() & 0xFF;
|
|
- basetime = basetime << 8 | (file.get() & 0xFF);
|
|
- basetime = basetime << 8 | (file.get() & 0xFF);
|
|
- basetime = basetime << 8 | (file.get() & 0xFF);
|
|
- rtc_.setBaseTime(basetime);
|
|
+ if(memoryCartridge) {
|
|
+ rtc_.setBaseTime(memoryCartridgeRtcBase);
|
|
+ } else {
|
|
+ std::ifstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::in);
|
|
+ if (file) {
|
|
+ unsigned basetime = file.get() & 0xFF;
|
|
+ basetime = basetime << 8 | (file.get() & 0xFF);
|
|
+ basetime = basetime << 8 | (file.get() & 0xFF);
|
|
+ basetime = basetime << 8 | (file.get() & 0xFF);
|
|
+ rtc_.setBaseTime(basetime);
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
|
|
+void Cartridge::clearMemorySavedData()
|
|
+{
|
|
+ memoryCartridgeRtcBase = 0;
|
|
+ memoryCartridgeSram.resize(0);
|
|
+}
|
|
+
|
|
void Cartridge::saveSavedata() {
|
|
std::string const &sbp = saveBasePath();
|
|
|
|
if (hasBattery(memptrs_.romdata()[0x147])) {
|
|
- std::ofstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::out);
|
|
- file.write(reinterpret_cast<char const *>(memptrs_.rambankdata()),
|
|
- memptrs_.rambankdataend() - memptrs_.rambankdata());
|
|
+ if(memoryCartridge) {
|
|
+ memoryCartridgeSram.resize(memptrs_.rambankdataend() - memptrs_.rambankdata());
|
|
+ memcpy(&memoryCartridgeSram[0], memptrs_.rambankdata(), memptrs_.rambankdataend() - memptrs_.rambankdata());
|
|
+ } else {
|
|
+ std::ofstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::out);
|
|
+ file.write(reinterpret_cast<const char*>(memptrs_.rambankdata()),
|
|
+ memptrs_.rambankdataend() - memptrs_.rambankdata());
|
|
+ }
|
|
}
|
|
|
|
if (hasRtc(memptrs_.romdata()[0x147])) {
|
|
- std::ofstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::out);
|
|
- unsigned long const basetime = rtc_.baseTime();
|
|
- file.put(basetime >> 24 & 0xFF);
|
|
- file.put(basetime >> 16 & 0xFF);
|
|
- file.put(basetime >> 8 & 0xFF);
|
|
- file.put(basetime & 0xFF);
|
|
+ if(memoryCartridge) {
|
|
+ memoryCartridgeRtcBase = rtc_.getBaseTime();
|
|
+ } else {
|
|
+ std::ofstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::out);
|
|
+ const unsigned basetime = rtc_.getBaseTime();
|
|
+ file.put(basetime >> 24 & 0xFF);
|
|
+ file.put(basetime >> 16 & 0xFF);
|
|
+ file.put(basetime >> 8 & 0xFF);
|
|
+ file.put(basetime & 0xFF);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -764,4 +843,36 @@ PakInfo const Cartridge::pakInfo(bool const multipakCompat) const {
|
|
return PakInfo();
|
|
}
|
|
|
|
+std::pair<unsigned char*, size_t> Cartridge::getSaveRam() {
|
|
+ size_t sramsize = memptrs_.rambankdataend() - memptrs_.rambankdata();
|
|
+ return std::make_pair(memptrs_.rambankdata(), sramsize);
|
|
+}
|
|
+
|
|
+std::pair<unsigned char*, size_t> Cartridge::getVideoRam() {
|
|
+ size_t vramsize = memptrs_.vramdataend() - memptrs_.vramdata();
|
|
+ return std::make_pair(memptrs_.vramdata(), vramsize);
|
|
+}
|
|
+
|
|
+std::pair<unsigned char*, size_t> Cartridge::getWorkRam() {
|
|
+ size_t worksize = memptrs_.wramdataend() - memptrs_.wramdata(0);
|
|
+ return std::make_pair(memptrs_.wramdata(0), worksize);
|
|
+}
|
|
+
|
|
+Cartridge::Cartridge(time_t (**_getCurrentTime)())
|
|
+ : rtc_(_getCurrentTime) {
|
|
+ memoryCartridge = true;
|
|
+}
|
|
+
|
|
+void Cartridge::loadOrSave(loadsave& state) {
|
|
+ memptrs_.loadOrSave(state);
|
|
+ rtc_.loadOrSave(state);
|
|
+ mbc_->loadOrSave(state);
|
|
+ unsigned ggsize = ggUndoList_.size();
|
|
+ state(ggsize);
|
|
+ if(!state.saving())
|
|
+ ggUndoList_.resize(ggsize);
|
|
+ for(size_t i = 0; i < ggsize; i++)
|
|
+ ggUndoList_[i].loadOrSave(state);
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/mem/cartridge.h b/libgambatte/src/mem/cartridge.h
|
|
index 4c2d7b4..dd342b6 100644
|
|
--- a/libgambatte/src/mem/cartridge.h
|
|
+++ b/libgambatte/src/mem/cartridge.h
|
|
@@ -26,9 +26,16 @@
|
|
#include "scoped_ptr.h"
|
|
#include <string>
|
|
#include <vector>
|
|
+#include "../loadsave.h"
|
|
+
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
|
|
namespace gambatte {
|
|
|
|
+class File;
|
|
+
|
|
class Mbc {
|
|
public:
|
|
virtual ~Mbc() {}
|
|
@@ -36,23 +43,16 @@ public:
|
|
virtual void saveState(SaveState::Mem &ss) const = 0;
|
|
virtual void loadState(SaveState::Mem const &ss) = 0;
|
|
virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned address, unsigned rombank) const = 0;
|
|
+ virtual void loadOrSave(loadsave& state) = 0;
|
|
};
|
|
|
|
class Cartridge {
|
|
public:
|
|
+ Cartridge(time_t (**_getCurrentTime)());
|
|
void setStatePtrs(SaveState &);
|
|
void saveState(SaveState &) const;
|
|
void loadState(SaveState const &);
|
|
bool loaded() const { return mbc_.get(); }
|
|
- unsigned char const * rmem(unsigned area) const { return memptrs_.rmem(area); }
|
|
- unsigned char * wmem(unsigned area) const { return memptrs_.wmem(area); }
|
|
- unsigned char * vramdata() const { return memptrs_.vramdata(); }
|
|
- unsigned char * romdata(unsigned area) const { return memptrs_.romdata(area); }
|
|
- unsigned char * wramdata(unsigned area) const { return memptrs_.wramdata(area); }
|
|
- unsigned char const * rdisabledRam() const { return memptrs_.rdisabledRam(); }
|
|
- unsigned char const * rsrambankptr() const { return memptrs_.rsrambankptr(); }
|
|
- unsigned char * wsrambankptr() const { return memptrs_.wsrambankptr(); }
|
|
- unsigned char * vrambankptr() const { return memptrs_.vrambankptr(); }
|
|
OamDmaSrc oamDmaSrc() const { return memptrs_.oamDmaSrc(); }
|
|
void setVrambank(unsigned bank) { memptrs_.setVrambank(bank); }
|
|
void setWrambank(unsigned bank) { memptrs_.setWrambank(bank); }
|
|
@@ -65,16 +65,40 @@ public:
|
|
void saveSavedata();
|
|
std::string const saveBasePath() const;
|
|
void setSaveDir(std::string const &dir);
|
|
- LoadRes loadROM(std::string const &romfile, bool forceDmg, bool multicartCompat);
|
|
char const * romTitle() const { return reinterpret_cast<char const *>(memptrs_.romdata() + 0x134); }
|
|
class PakInfo const pakInfo(bool multicartCompat) const;
|
|
void setGameGenie(std::string const &codes);
|
|
+ const unsigned char * rmem(unsigned area) const { return memptrs_.rmem(area); }
|
|
+ unsigned char * wmem(unsigned area) const { return memptrs_.wmem(area); }
|
|
+ unsigned char * vramdata() const { return memptrs_.vramdata(); }
|
|
+ unsigned char * romdata(unsigned area) const { return memptrs_.romdata(area); }
|
|
+ unsigned char * wramdata(unsigned area) const { return memptrs_.wramdata(area); }
|
|
+ const unsigned char * rdisabledRam() const { return memptrs_.rdisabledRam(); }
|
|
+ const unsigned char * rsrambankptr() const { return memptrs_.rsrambankptr(); }
|
|
+ unsigned char * wsrambankptr() const { return memptrs_.wsrambankptr(); }
|
|
+ unsigned char * vrambankptr() const { return memptrs_.vrambankptr(); }
|
|
+
|
|
+ void loadOrSave(loadsave& state);
|
|
+ void setRtcBase(time_t time) { rtc_.setBaseTime(time); }
|
|
+ time_t getRtcBase() { return rtc_.getBaseTime(); }
|
|
+ std::pair<unsigned char*, size_t> getWorkRam();
|
|
+ std::pair<unsigned char*, size_t> getSaveRam();
|
|
+ std::pair<unsigned char*, size_t> getVideoRam();
|
|
+ LoadRes loadROM(const std::string &romfile, bool forceDmg, bool multicartCompat);
|
|
+ LoadRes loadROM(const unsigned char* image, size_t isize, bool forceDmg, bool multicartCompat);
|
|
+ LoadRes loadROM(File* rom, const bool forceDmg, const bool multicartCompat, const std::string& filename);
|
|
+ void clearMemorySavedData();
|
|
|
|
private:
|
|
struct AddrData {
|
|
- unsigned long addr;
|
|
+ unsigned addr;
|
|
unsigned char data;
|
|
- AddrData(unsigned long addr, unsigned data) : addr(addr), data(data) {}
|
|
+ AddrData(unsigned addr, unsigned data) : addr(addr), data(data) {}
|
|
+ AddrData() {}
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ state(addr);
|
|
+ state(data);
|
|
+ }
|
|
};
|
|
|
|
MemPtrs memptrs_;
|
|
@@ -83,6 +107,9 @@ private:
|
|
std::string defaultSaveBasePath_;
|
|
std::string saveDir_;
|
|
std::vector<AddrData> ggUndoList_;
|
|
+ bool memoryCartridge;
|
|
+ time_t memoryCartridgeRtcBase;
|
|
+ std::vector<unsigned char> memoryCartridgeSram;
|
|
|
|
void applyGameGenie(std::string const &code);
|
|
};
|
|
diff --git a/libgambatte/src/mem/memptrs.cpp b/libgambatte/src/mem/memptrs.cpp
|
|
index e29b855..f351d94 100644
|
|
--- a/libgambatte/src/mem/memptrs.cpp
|
|
+++ b/libgambatte/src/mem/memptrs.cpp
|
|
@@ -20,6 +20,10 @@
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
MemPtrs::MemPtrs()
|
|
@@ -43,13 +47,11 @@ MemPtrs::~MemPtrs() {
|
|
|
|
void MemPtrs::reset(unsigned const rombanks, unsigned const rambanks, unsigned const wrambanks) {
|
|
delete []memchunk_;
|
|
- memchunk_ = new unsigned char[
|
|
- 0x4000
|
|
- + rombanks * 0x4000ul
|
|
- + 0x4000
|
|
- + rambanks * 0x2000ul
|
|
- + wrambanks * 0x1000ul
|
|
- + 0x4000];
|
|
+ memchunk_size = 0x4000 + rombanks * 0x4000ul + 0x4000 + rambanks * 0x2000ul + wrambanks * 0x1000ul + 0x4000;
|
|
+ memchunk_ = new unsigned char[memchunk_size];
|
|
+
|
|
+ //FIXME: Make this random.
|
|
+ memset(memchunk_, 0, memchunk_size);
|
|
|
|
romdata_[0] = romdata();
|
|
rambankdata_ = romdata_[0] + rombanks * 0x4000ul + 0x4000;
|
|
@@ -155,4 +157,26 @@ void MemPtrs::disconnectOamDmaAreas() {
|
|
}
|
|
}
|
|
|
|
+void MemPtrs::loadOrSave(loadsave& state)
|
|
+{
|
|
+ state(memchunk_, 0x4000);
|
|
+ state(romdataend(), memchunk_size - (romdataend() - memchunk_));
|
|
+ int oamDmaSrc_2 = oamDmaSrc_;
|
|
+ state(oamDmaSrc_2);
|
|
+ oamDmaSrc_ = (OamDmaSrc)oamDmaSrc_2;
|
|
+ //Rmem is constant.
|
|
+ for(unsigned i = 0; i < 0x10; i++)
|
|
+ state(wmem_[i], memchunk_);
|
|
+ for(unsigned i = 0; i < 0x10; i++)
|
|
+ state(rmem_[i], memchunk_);
|
|
+ state(romdata_[0], memchunk_);
|
|
+ state(romdata_[1], memchunk_);
|
|
+ state(rambankdata_, memchunk_);
|
|
+ state(rsrambankptr_, memchunk_);
|
|
+ state(wsrambankptr_, memchunk_);
|
|
+ state(wramdataend_, memchunk_);
|
|
+ state(vrambankptr_, memchunk_);
|
|
+ //memchunk_size is cart constant, not saved.
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/mem/memptrs.h b/libgambatte/src/mem/memptrs.h
|
|
index bd0e176..6553955 100644
|
|
--- a/libgambatte/src/mem/memptrs.h
|
|
+++ b/libgambatte/src/mem/memptrs.h
|
|
@@ -19,6 +19,12 @@
|
|
#ifndef MEMPTRS_H
|
|
#define MEMPTRS_H
|
|
|
|
+#include "../loadsave.h"
|
|
+
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
enum OamDmaSrc { oam_dma_src_rom,
|
|
@@ -60,6 +66,7 @@ public:
|
|
void setWrambank(unsigned bank);
|
|
void setOamDmaSrc(OamDmaSrc oamDmaSrc);
|
|
|
|
+ void loadOrSave(loadsave& state);
|
|
private:
|
|
unsigned char const *rmem_[0x10];
|
|
unsigned char *wmem_[0x10];
|
|
@@ -72,6 +79,7 @@ private:
|
|
unsigned char *rambankdata_;
|
|
unsigned char *wramdataend_;
|
|
OamDmaSrc oamDmaSrc_;
|
|
+ size_t memchunk_size;
|
|
|
|
MemPtrs(MemPtrs const &);
|
|
MemPtrs & operator=(MemPtrs const &);
|
|
diff --git a/libgambatte/src/mem/rtc.cpp b/libgambatte/src/mem/rtc.cpp
|
|
index 1a46867..4a98bbe 100644
|
|
--- a/libgambatte/src/mem/rtc.cpp
|
|
+++ b/libgambatte/src/mem/rtc.cpp
|
|
@@ -19,9 +19,13 @@
|
|
#include "rtc.h"
|
|
#include "../savestate.h"
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
-Rtc::Rtc()
|
|
+Rtc::Rtc(time_t (**_getCurrentTime)())
|
|
: activeData_(0)
|
|
, activeSet_(0)
|
|
, baseTime_(0)
|
|
@@ -34,11 +38,12 @@ Rtc::Rtc()
|
|
, dataS_(0)
|
|
, enabled_(false)
|
|
, lastLatchData_(false)
|
|
+, getCurrentTime(_getCurrentTime)
|
|
{
|
|
}
|
|
|
|
void Rtc::doLatch() {
|
|
- std::time_t tmp = (dataDh_ & 0x40 ? haltTime_ : std::time(0)) - baseTime_;
|
|
+ std::time_t tmp = (dataDh_ & 0x40 ? haltTime_ : (*getCurrentTime)()) - baseTime_;
|
|
|
|
while (tmp > 0x1FF * 86400) {
|
|
baseTime_ += 0x1FF * 86400;
|
|
@@ -112,44 +117,77 @@ void Rtc::loadState(SaveState const &state) {
|
|
}
|
|
|
|
void Rtc::setDh(unsigned const newDh) {
|
|
- std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : std::time(0);
|
|
+ std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : (*getCurrentTime)();
|
|
std::time_t const oldHighdays = ((unixtime - baseTime_) / 86400) & 0x100;
|
|
baseTime_ += oldHighdays * 86400;
|
|
baseTime_ -= ((newDh & 0x1) << 8) * 86400;
|
|
|
|
if ((dataDh_ ^ newDh) & 0x40) {
|
|
if (newDh & 0x40)
|
|
- haltTime_ = std::time(0);
|
|
+ haltTime_ = (*getCurrentTime)();
|
|
else
|
|
- baseTime_ += std::time(0) - haltTime_;
|
|
+ baseTime_ += (*getCurrentTime)() - haltTime_;
|
|
+
|
|
}
|
|
}
|
|
|
|
void Rtc::setDl(unsigned const newLowdays) {
|
|
- std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : std::time(0);
|
|
+ std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : (*getCurrentTime)();
|
|
std::time_t const oldLowdays = ((unixtime - baseTime_) / 86400) & 0xFF;
|
|
baseTime_ += oldLowdays * 86400;
|
|
baseTime_ -= newLowdays * 86400;
|
|
}
|
|
|
|
void Rtc::setH(unsigned const newHours) {
|
|
- std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : std::time(0);
|
|
+ std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : (*getCurrentTime)();
|
|
std::time_t const oldHours = ((unixtime - baseTime_) / 3600) % 24;
|
|
baseTime_ += oldHours * 3600;
|
|
baseTime_ -= newHours * 3600;
|
|
}
|
|
|
|
void Rtc::setM(unsigned const newMinutes) {
|
|
- std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : std::time(0);
|
|
+ std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : (*getCurrentTime)();
|
|
std::time_t const oldMinutes = ((unixtime - baseTime_) / 60) % 60;
|
|
baseTime_ += oldMinutes * 60;
|
|
baseTime_ -= newMinutes * 60;
|
|
}
|
|
|
|
void Rtc::setS(unsigned const newSeconds) {
|
|
- std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : std::time(0);
|
|
+ std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : (*getCurrentTime)();
|
|
baseTime_ += (unixtime - baseTime_) % 60;
|
|
baseTime_ -= newSeconds;
|
|
}
|
|
|
|
+void Rtc::loadOrSave(loadsave& state)
|
|
+{
|
|
+ state.startEnumeration();
|
|
+ state.enumerate<unsigned char*>(activeData_, NULL, 0);
|
|
+ state.enumerate(activeData_, &dataDh_, 1);
|
|
+ state.enumerate(activeData_, &dataDl_, 2);
|
|
+ state.enumerate(activeData_, &dataH_, 3);
|
|
+ state.enumerate(activeData_, &dataM_, 4);
|
|
+ state.enumerate(activeData_, &dataS_, 5);
|
|
+ state.endEnumeration();
|
|
+
|
|
+ state.startEnumeration();
|
|
+ state.enumerate<void (gambatte::Rtc::*)(unsigned int)>(activeSet_, NULL, 0);
|
|
+ state.enumerate(activeSet_, &Rtc::setDh, 1);
|
|
+ state.enumerate(activeSet_, &Rtc::setDl, 2);
|
|
+ state.enumerate(activeSet_, &Rtc::setH, 3);
|
|
+ state.enumerate(activeSet_, &Rtc::setM, 4);
|
|
+ state.enumerate(activeSet_, &Rtc::setS, 5);
|
|
+ state.endEnumeration();
|
|
+
|
|
+ state.time(baseTime_);
|
|
+ state.time(haltTime_);
|
|
+ state(index_);
|
|
+ state(dataDh_);
|
|
+ state(dataDl_);
|
|
+ state(dataH_);
|
|
+ state(dataM_);
|
|
+ state(dataS_);
|
|
+ state(enabled_);
|
|
+ state(lastLatchData_);
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/mem/rtc.h b/libgambatte/src/mem/rtc.h
|
|
index 2408067..81da102 100644
|
|
--- a/libgambatte/src/mem/rtc.h
|
|
+++ b/libgambatte/src/mem/rtc.h
|
|
@@ -20,6 +20,12 @@
|
|
#define RTC_H
|
|
|
|
#include <ctime>
|
|
+#include "../loadsave.h"
|
|
+
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
|
|
namespace gambatte {
|
|
|
|
@@ -27,7 +33,7 @@ struct SaveState;
|
|
|
|
class Rtc {
|
|
public:
|
|
- Rtc();
|
|
+ Rtc(time_t (**_getCurrentTime)());
|
|
unsigned char const * activeData() const { return activeData_; }
|
|
std::time_t baseTime() const { return baseTime_; }
|
|
void setBaseTime(std::time_t baseTime) { baseTime_ = baseTime; }
|
|
@@ -56,6 +62,9 @@ public:
|
|
*activeData_ = data;
|
|
}
|
|
|
|
+ std::time_t getBaseTime() const { return baseTime_; }
|
|
+
|
|
+ void loadOrSave(loadsave& state);
|
|
private:
|
|
unsigned char *activeData_;
|
|
void (Rtc::*activeSet_)(unsigned);
|
|
@@ -77,6 +86,7 @@ private:
|
|
void setH(unsigned newHours);
|
|
void setM(unsigned newMinutes);
|
|
void setS(unsigned newSeconds);
|
|
+ time_t (**getCurrentTime)();
|
|
};
|
|
|
|
}
|
|
diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp
|
|
index 529e9f2..cc76f96 100644
|
|
--- a/libgambatte/src/memory.cpp
|
|
+++ b/libgambatte/src/memory.cpp
|
|
@@ -23,9 +23,13 @@
|
|
#include "video.h"
|
|
#include <cstring>
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
-Memory::Memory(Interrupter const &interrupter)
|
|
+Memory::Memory(Interrupter const &interrupter, time_t (**_getCurrentTime)())
|
|
: getInput_(0)
|
|
, divLastUpdate_(0)
|
|
, lastOamDmaUpdate_(disabled_time)
|
|
@@ -36,6 +40,7 @@ Memory::Memory(Interrupter const &interrupter)
|
|
, oamDmaPos_(0xFE)
|
|
, serialCnt_(0)
|
|
, blanklcd_(false)
|
|
+, cart_(_getCurrentTime)
|
|
{
|
|
intreq_.setEventTime<intevent_blit>(144 * 456ul);
|
|
intreq_.setEventTime<intevent_end>(0);
|
|
@@ -49,7 +54,7 @@ void Memory::setStatePtrs(SaveState &state) {
|
|
psg_.setStatePtrs(state);
|
|
}
|
|
|
|
-unsigned long Memory::saveState(SaveState &state, unsigned long cc) {
|
|
+unsigned Memory::saveState(SaveState &state, unsigned cc) {
|
|
cc = resetCounters(cc);
|
|
nontrivial_ff_read(0x05, cc);
|
|
nontrivial_ff_read(0x0F, cc);
|
|
@@ -72,7 +77,7 @@ unsigned long Memory::saveState(SaveState &state, unsigned long cc) {
|
|
return cc;
|
|
}
|
|
|
|
-static int serialCntFrom(unsigned long cyclesUntilDone, bool cgbFast) {
|
|
+static int serialCntFrom(unsigned cyclesUntilDone, bool cgbFast) {
|
|
return cgbFast ? (cyclesUntilDone + 0xF) >> 4 : (cyclesUntilDone + 0x1FF) >> 9;
|
|
}
|
|
|
|
@@ -118,7 +123,7 @@ void Memory::loadState(SaveState const &state) {
|
|
std::memset(cart_.vramdata() + 0x2000, 0, 0x2000);
|
|
}
|
|
|
|
-void Memory::setEndtime(unsigned long cc, unsigned long inc) {
|
|
+void Memory::setEndtime(unsigned cc, unsigned inc) {
|
|
if (intreq_.eventTime(intevent_blit) <= cc) {
|
|
intreq_.setEventTime<intevent_blit>(intreq_.eventTime(intevent_blit)
|
|
+ (70224 << isDoubleSpeed()));
|
|
@@ -127,7 +132,7 @@ void Memory::setEndtime(unsigned long cc, unsigned long inc) {
|
|
intreq_.setEventTime<intevent_end>(cc + (inc << isDoubleSpeed()));
|
|
}
|
|
|
|
-void Memory::updateSerial(unsigned long const cc) {
|
|
+void Memory::updateSerial(unsigned const cc) {
|
|
if (intreq_.eventTime(intevent_serial) != disabled_time) {
|
|
if (intreq_.eventTime(intevent_serial) <= cc) {
|
|
ioamhram_[0x101] = (((ioamhram_[0x101] + 1) << serialCnt_) - 1) & 0xFF;
|
|
@@ -143,18 +148,18 @@ void Memory::updateSerial(unsigned long const cc) {
|
|
}
|
|
}
|
|
|
|
-void Memory::updateTimaIrq(unsigned long cc) {
|
|
+void Memory::updateTimaIrq(unsigned cc) {
|
|
while (intreq_.eventTime(intevent_tima) <= cc)
|
|
tima_.doIrqEvent(TimaInterruptRequester(intreq_));
|
|
}
|
|
|
|
-void Memory::updateIrqs(unsigned long cc) {
|
|
+void Memory::updateIrqs(unsigned cc) {
|
|
updateSerial(cc);
|
|
updateTimaIrq(cc);
|
|
lcd_.update(cc);
|
|
}
|
|
|
|
-unsigned long Memory::event(unsigned long cc) {
|
|
+unsigned Memory::event(unsigned cc) {
|
|
if (lastOamDmaUpdate_ != disabled_time)
|
|
updateOamDma(cc);
|
|
|
|
@@ -177,10 +182,10 @@ unsigned long Memory::event(unsigned long cc) {
|
|
case intevent_blit:
|
|
{
|
|
bool const lcden = ioamhram_[0x140] & lcdc_en;
|
|
- unsigned long blitTime = intreq_.eventTime(intevent_blit);
|
|
+ unsigned blitTime = intreq_.eventTime(intevent_blit);
|
|
|
|
if (lcden | blanklcd_) {
|
|
- lcd_.updateScreen(blanklcd_, cc);
|
|
+ lcd_.updateScreen(blanklcd_, cc, videoBuf_, pitch_);
|
|
intreq_.setEventTime<intevent_blit>(disabled_time);
|
|
intreq_.setEventTime<intevent_end>(disabled_time);
|
|
|
|
@@ -198,7 +203,7 @@ unsigned long Memory::event(unsigned long cc) {
|
|
break;
|
|
case intevent_oam:
|
|
intreq_.setEventTime<intevent_oam>(lastOamDmaUpdate_ == disabled_time
|
|
- ? static_cast<unsigned long>(disabled_time)
|
|
+ ? static_cast<unsigned>(disabled_time)
|
|
: intreq_.eventTime(intevent_oam) + 0xA0 * 4);
|
|
break;
|
|
case intevent_dma:
|
|
@@ -211,7 +216,7 @@ unsigned long Memory::event(unsigned long cc) {
|
|
|
|
ackDmaReq(intreq_);
|
|
|
|
- if ((static_cast<unsigned long>(dmaDest) + length) & 0x10000) {
|
|
+ if ((static_cast<unsigned>(dmaDest) + length) & 0x10000) {
|
|
length = 0x10000 - dmaDest;
|
|
ioamhram_[0x155] |= 0x80;
|
|
}
|
|
@@ -222,7 +227,7 @@ unsigned long Memory::event(unsigned long cc) {
|
|
dmaLength = 0;
|
|
|
|
{
|
|
- unsigned long lOamDmaUpdate = lastOamDmaUpdate_;
|
|
+ unsigned lOamDmaUpdate = lastOamDmaUpdate_;
|
|
lastOamDmaUpdate_ = disabled_time;
|
|
|
|
while (length--) {
|
|
@@ -304,7 +309,7 @@ unsigned long Memory::event(unsigned long cc) {
|
|
return cc;
|
|
}
|
|
|
|
-unsigned long Memory::stop(unsigned long cc) {
|
|
+unsigned Memory::stop(unsigned cc) {
|
|
cc += 4 + 4 * isDoubleSpeed();
|
|
|
|
if (ioamhram_[0x14D] & isCgb()) {
|
|
@@ -328,29 +333,29 @@ unsigned long Memory::stop(unsigned long cc) {
|
|
return cc;
|
|
}
|
|
|
|
-static void decCycles(unsigned long &counter, unsigned long dec) {
|
|
+static void decCycles(unsigned &counter, unsigned dec) {
|
|
if (counter != disabled_time)
|
|
counter -= dec;
|
|
}
|
|
|
|
-void Memory::decEventCycles(IntEventId eventId, unsigned long dec) {
|
|
+void Memory::decEventCycles(IntEventId eventId, unsigned dec) {
|
|
if (intreq_.eventTime(eventId) != disabled_time)
|
|
intreq_.setEventTime(eventId, intreq_.eventTime(eventId) - dec);
|
|
}
|
|
|
|
-unsigned long Memory::resetCounters(unsigned long cc) {
|
|
+unsigned Memory::resetCounters(unsigned cc) {
|
|
if (lastOamDmaUpdate_ != disabled_time)
|
|
updateOamDma(cc);
|
|
|
|
updateIrqs(cc);
|
|
|
|
{
|
|
- unsigned long divinc = (cc - divLastUpdate_) >> 8;
|
|
+ unsigned divinc = (cc - divLastUpdate_) >> 8;
|
|
ioamhram_[0x104] = (ioamhram_[0x104] + divinc) & 0xFF;
|
|
divLastUpdate_ += divinc << 8;
|
|
}
|
|
|
|
- unsigned long const dec = cc < 0x10000
|
|
+ unsigned const dec = cc < 0x10000
|
|
? 0
|
|
: (cc & ~0x7FFFul) - 0x8000;
|
|
decCycles(divLastUpdate_, dec);
|
|
@@ -361,7 +366,7 @@ unsigned long Memory::resetCounters(unsigned long cc) {
|
|
decEventCycles(intevent_end, dec);
|
|
decEventCycles(intevent_unhalt, dec);
|
|
|
|
- unsigned long const oldCC = cc;
|
|
+ unsigned const oldCC = cc;
|
|
cc -= dec;
|
|
intreq_.resetCc(oldCC, cc);
|
|
tima_.resetCc(oldCC, cc, TimaInterruptRequester(intreq_));
|
|
@@ -388,7 +393,7 @@ void Memory::updateInput() {
|
|
ioamhram_[0x100] &= button;
|
|
}
|
|
|
|
-void Memory::updateOamDma(unsigned long const cc) {
|
|
+void Memory::updateOamDma(unsigned const cc) {
|
|
unsigned char const *const oamDmaSrc = oamDmaSrcPtr();
|
|
unsigned cycles = (cc - lastOamDmaUpdate_) >> 2;
|
|
|
|
@@ -441,17 +446,17 @@ unsigned char const * Memory::oamDmaSrcPtr() const {
|
|
return ioamhram_[0x146] == 0xFF && !isCgb() ? oamDmaSrcZero() : cart_.rdisabledRam();
|
|
}
|
|
|
|
-void Memory::startOamDma(unsigned long cc) {
|
|
+void Memory::startOamDma(unsigned cc) {
|
|
lcd_.oamChange(cart_.rdisabledRam(), cc);
|
|
}
|
|
|
|
-void Memory::endOamDma(unsigned long cc) {
|
|
+void Memory::endOamDma(unsigned cc) {
|
|
oamDmaPos_ = 0xFE;
|
|
cart_.setOamDmaSrc(oam_dma_src_off);
|
|
lcd_.oamChange(ioamhram_, cc);
|
|
}
|
|
|
|
-unsigned Memory::nontrivial_ff_read(unsigned const p, unsigned long const cc) {
|
|
+unsigned Memory::nontrivial_ff_read(unsigned const p, unsigned const cc) {
|
|
if (lastOamDmaUpdate_ != disabled_time)
|
|
updateOamDma(cc);
|
|
|
|
@@ -465,7 +470,7 @@ unsigned Memory::nontrivial_ff_read(unsigned const p, unsigned long const cc) {
|
|
break;
|
|
case 0x04:
|
|
{
|
|
- unsigned long divcycles = (cc - divLastUpdate_) >> 8;
|
|
+ unsigned divcycles = (cc - divLastUpdate_) >> 8;
|
|
ioamhram_[0x104] = (ioamhram_[0x104] + divcycles) & 0xFF;
|
|
divLastUpdate_ += divcycles << 8;
|
|
}
|
|
@@ -545,7 +550,7 @@ static bool isInOamDmaConflictArea(OamDmaSrc const oamDmaSrc, unsigned const p,
|
|
&& p - a[oamDmaSrc].exceptAreaLower >= a[oamDmaSrc].exceptAreaWidth;
|
|
}
|
|
|
|
-unsigned Memory::nontrivial_read(unsigned const p, unsigned long const cc) {
|
|
+unsigned Memory::nontrivial_read(unsigned const p, unsigned const cc) {
|
|
if (p < 0xFF80) {
|
|
if (lastOamDmaUpdate_ != disabled_time) {
|
|
updateOamDma(cc);
|
|
@@ -585,7 +590,7 @@ unsigned Memory::nontrivial_read(unsigned const p, unsigned long const cc) {
|
|
return ioamhram_[p - 0xFE00];
|
|
}
|
|
|
|
-void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long const cc) {
|
|
+void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned const cc) {
|
|
if (lastOamDmaUpdate_ != disabled_time)
|
|
updateOamDma(cc);
|
|
|
|
@@ -1005,7 +1010,7 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long
|
|
ioamhram_[p + 0x100] = data;
|
|
}
|
|
|
|
-void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned long const cc) {
|
|
+void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned const cc) {
|
|
if (lastOamDmaUpdate_ != disabled_time) {
|
|
updateOamDma(cc);
|
|
|
|
@@ -1043,20 +1048,53 @@ void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned lo
|
|
ioamhram_[p - 0xFE00] = data;
|
|
}
|
|
|
|
-LoadRes Memory::loadROM(std::string const &romfile, bool const forceDmg, bool const multicartCompat) {
|
|
- if (LoadRes const fail = cart_.loadROM(romfile, forceDmg, multicartCompat))
|
|
- return fail;
|
|
-
|
|
+void Memory::postLoadRom()
|
|
+{
|
|
psg_.init(cart_.isCgb());
|
|
lcd_.reset(ioamhram_, cart_.vramdata(), cart_.isCgb());
|
|
interrupter_.setGameShark(std::string());
|
|
+}
|
|
|
|
+LoadRes Memory::loadROM(std::string const &romfile, bool const forceDmg, bool const multicartCompat) {
|
|
+ if (LoadRes const fail = cart_.loadROM(romfile, forceDmg, multicartCompat))
|
|
+ return fail;
|
|
+ postLoadRom();
|
|
return LOADRES_OK;
|
|
}
|
|
|
|
-std::size_t Memory::fillSoundBuffer(unsigned long cc) {
|
|
+LoadRes Memory::loadROM(const unsigned char* image, size_t isize, const bool forceDmg, const bool multicartCompat) {
|
|
+ if (LoadRes fail = cart_.loadROM(image, isize, forceDmg, multicartCompat))
|
|
+ return fail;
|
|
+ postLoadRom();
|
|
+ return LOADRES_OK;
|
|
+}
|
|
+
|
|
+unsigned Memory::fillSoundBuffer(unsigned cc) {
|
|
psg_.generateSamples(cc, isDoubleSpeed());
|
|
return psg_.fillBuffer();
|
|
}
|
|
|
|
+void Memory::setDmgPaletteColor(unsigned palNum, unsigned colorNum, uint_least32_t rgb32) {
|
|
+ lcd_.setDmgPaletteColor(palNum, colorNum, rgb32);
|
|
+}
|
|
+
|
|
+void Memory::loadOrSave(loadsave& state)
|
|
+{
|
|
+ state(ioamhram_, 0x200);
|
|
+ //Don't save getInput, it has no state.
|
|
+ state(divLastUpdate_);
|
|
+ state(lastOamDmaUpdate_);
|
|
+ intreq_.loadOrSave(state);
|
|
+ cart_.loadOrSave(state);
|
|
+ tima_.loadOrSave(state);
|
|
+ lcd_.loadOrSave(state);
|
|
+ psg_.loadOrSave(state);
|
|
+ interrupter_.loadOrSave(state);
|
|
+ state(dmaSource_);
|
|
+ state(dmaDestination_);
|
|
+ state(oamDmaPos_);
|
|
+ state(serialCnt_);
|
|
+ state(blanklcd_);
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h
|
|
index e612dc3..a531930 100644
|
|
--- a/libgambatte/src/memory.h
|
|
+++ b/libgambatte/src/memory.h
|
|
@@ -19,6 +19,10 @@
|
|
#ifndef MEMORY_H
|
|
#define MEMORY_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include "mem/cartridge.h"
|
|
#include "interrupter.h"
|
|
#include "pakinfo.h"
|
|
@@ -33,12 +37,13 @@ class FilterInfo;
|
|
|
|
class Memory {
|
|
public:
|
|
- explicit Memory(Interrupter const &interrupter);
|
|
+ explicit Memory(Interrupter const &interrupter, time_t (**gettime)());
|
|
bool loaded() const { return cart_.loaded(); }
|
|
char const * romTitle() const { return cart_.romTitle(); }
|
|
PakInfo const pakInfo(bool multicartCompat) const { return cart_.pakInfo(multicartCompat); }
|
|
void setStatePtrs(SaveState &state);
|
|
- unsigned long saveState(SaveState &state, unsigned long cc);
|
|
+ unsigned saveState(SaveState &state, unsigned cc);
|
|
+ void loadOrSave(loadsave& state);
|
|
void loadState(SaveState const &state);
|
|
void loadSavedata() { cart_.loadSavedata(); }
|
|
void saveSavedata() { cart_.saveSavedata(); }
|
|
@@ -48,14 +53,14 @@ public:
|
|
lcd_.setOsdElement(osdElement);
|
|
}
|
|
|
|
- unsigned long stop(unsigned long cycleCounter);
|
|
+ unsigned stop(unsigned cycleCounter);
|
|
bool isCgb() const { return lcd_.isCgb(); }
|
|
bool ime() const { return intreq_.ime(); }
|
|
bool halted() const { return intreq_.halted(); }
|
|
- unsigned long nextEventTime() const { return intreq_.minEventTime(); }
|
|
+ unsigned nextEventTime() const { return intreq_.minEventTime(); }
|
|
bool isActive() const { return intreq_.eventTime(intevent_end) != disabled_time; }
|
|
|
|
- long cyclesSinceBlit(unsigned long cc) const {
|
|
+ signed cyclesSinceBlit(unsigned cc) const {
|
|
if (cc < intreq_.eventTime(intevent_blit))
|
|
return -1;
|
|
|
|
@@ -63,48 +68,55 @@ public:
|
|
}
|
|
|
|
void halt() { intreq_.halt(); }
|
|
- void ei(unsigned long cycleCounter) { if (!ime()) { intreq_.ei(cycleCounter); } }
|
|
+ void ei(unsigned cycleCounter) { if (!ime()) { intreq_.ei(cycleCounter); } }
|
|
void di() { intreq_.di(); }
|
|
|
|
- unsigned ff_read(unsigned p, unsigned long cc) {
|
|
+ unsigned ff_read(unsigned p, unsigned cc) {
|
|
return p < 0x80 ? nontrivial_ff_read(p, cc) : ioamhram_[p + 0x100];
|
|
}
|
|
|
|
- unsigned read(unsigned p, unsigned long cc) {
|
|
+ unsigned read(unsigned p, unsigned cc) {
|
|
return cart_.rmem(p >> 12) ? cart_.rmem(p >> 12)[p] : nontrivial_read(p, cc);
|
|
}
|
|
|
|
- void write(unsigned p, unsigned data, unsigned long cc) {
|
|
+ void write(unsigned p, unsigned data, unsigned cc) {
|
|
if (cart_.wmem(p >> 12)) {
|
|
cart_.wmem(p >> 12)[p] = data;
|
|
} else
|
|
nontrivial_write(p, data, cc);
|
|
}
|
|
|
|
- void ff_write(unsigned p, unsigned data, unsigned long cc) {
|
|
+ void ff_write(unsigned p, unsigned data, unsigned cc) {
|
|
if (p - 0x80u < 0x7Fu) {
|
|
ioamhram_[p + 0x100] = data;
|
|
} else
|
|
nontrivial_ff_write(p, data, cc);
|
|
}
|
|
|
|
- unsigned long event(unsigned long cycleCounter);
|
|
- unsigned long resetCounters(unsigned long cycleCounter);
|
|
- LoadRes loadROM(std::string const &romfile, bool forceDmg, bool multicartCompat);
|
|
- void setSaveDir(std::string const &dir) { cart_.setSaveDir(dir); }
|
|
- void setInputGetter(InputGetter *getInput) { getInput_ = getInput; }
|
|
- void setEndtime(unsigned long cc, unsigned long inc);
|
|
- void setSoundBuffer(uint_least32_t *buf) { psg_.setBuffer(buf); }
|
|
- std::size_t fillSoundBuffer(unsigned long cc);
|
|
+ LoadRes loadROM(const std::string &romfile, bool forceDmg, bool multicartCompat);
|
|
+ LoadRes loadROM(const unsigned char* image, size_t isize, bool forceDmg, bool multicartCompat);
|
|
|
|
- void setVideoBuffer(uint_least32_t *videoBuf, std::ptrdiff_t pitch) {
|
|
- lcd_.setVideoBuffer(videoBuf, pitch);
|
|
+ void setVideoBuffer(uint_least32_t *const videoBuf, std::ptrdiff_t pitch) {
|
|
+ videoBuf_ = videoBuf;
|
|
+ pitch_ = pitch;
|
|
}
|
|
|
|
- void setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32) {
|
|
- lcd_.setDmgPaletteColor(palNum, colorNum, rgb32);
|
|
- }
|
|
+ void setRtcBase(time_t time) { cart_.setRtcBase(time); }
|
|
+ time_t getRtcBase() { return cart_.getRtcBase(); }
|
|
+ std::pair<unsigned char*, size_t> getWorkRam() { return cart_.getWorkRam(); }
|
|
+ std::pair<unsigned char*, size_t> getSaveRam() { return cart_.getSaveRam(); }
|
|
+ std::pair<unsigned char*, size_t> getIoRam() { return std::make_pair(ioamhram_, sizeof(ioamhram_)); }
|
|
+ std::pair<unsigned char*, size_t> getVideoRam() { return cart_.getVideoRam(); };
|
|
+
|
|
+ unsigned event(unsigned cycleCounter);
|
|
+ unsigned resetCounters(unsigned cycleCounter);
|
|
+ void setSaveDir(std::string const &dir) { cart_.setSaveDir(dir); }
|
|
+ void setInputGetter(InputGetter *getInput) { getInput_ = getInput; }
|
|
+ void setEndtime(unsigned cc, unsigned inc);
|
|
+ void setSoundBuffer(uint_least32_t *buf) { psg_.setBuffer(buf); }
|
|
+ unsigned fillSoundBuffer(unsigned cc);
|
|
|
|
+ void setDmgPaletteColor(unsigned palNum, unsigned colorNum, uint_least32_t rgb32);
|
|
void setGameGenie(std::string const &codes) { cart_.setGameGenie(codes); }
|
|
void setGameShark(std::string const &codes) { interrupter_.setGameShark(codes); }
|
|
|
|
@@ -112,8 +124,8 @@ private:
|
|
Cartridge cart_;
|
|
unsigned char ioamhram_[0x200];
|
|
InputGetter *getInput_;
|
|
- unsigned long divLastUpdate_;
|
|
- unsigned long lastOamDmaUpdate_;
|
|
+ unsigned divLastUpdate_;
|
|
+ unsigned lastOamDmaUpdate_;
|
|
InterruptRequester intreq_;
|
|
Tima tima_;
|
|
LCD lcd_;
|
|
@@ -124,22 +136,25 @@ private:
|
|
unsigned char oamDmaPos_;
|
|
unsigned char serialCnt_;
|
|
bool blanklcd_;
|
|
+ uint_least32_t* videoBuf_;
|
|
+ unsigned pitch_;
|
|
|
|
void updateInput();
|
|
- void decEventCycles(IntEventId eventId, unsigned long dec);
|
|
+ void decEventCycles(IntEventId eventId, unsigned dec);
|
|
void oamDmaInitSetup();
|
|
- void updateOamDma(unsigned long cycleCounter);
|
|
- void startOamDma(unsigned long cycleCounter);
|
|
- void endOamDma(unsigned long cycleCounter);
|
|
+ void updateOamDma(unsigned cycleCounter);
|
|
+ void startOamDma(unsigned cycleCounter);
|
|
+ void endOamDma(unsigned cycleCounter);
|
|
unsigned char const * 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);
|
|
- void updateSerial(unsigned long cc);
|
|
- void updateTimaIrq(unsigned long cc);
|
|
- void updateIrqs(unsigned long cc);
|
|
+ unsigned nontrivial_ff_read(unsigned p, unsigned cycleCounter);
|
|
+ unsigned nontrivial_read(unsigned p, unsigned cycleCounter);
|
|
+ void nontrivial_ff_write(unsigned p, unsigned data, unsigned cycleCounter);
|
|
+ void nontrivial_write(unsigned p, unsigned data, unsigned cycleCounter);
|
|
+ void updateSerial(unsigned cc);
|
|
+ void updateTimaIrq(unsigned cc);
|
|
+ void updateIrqs(unsigned cc);
|
|
bool isDoubleSpeed() const { return lcd_.isDoubleSpeed(); }
|
|
+ void postLoadRom();
|
|
};
|
|
|
|
}
|
|
diff --git a/libgambatte/src/minkeeper.h b/libgambatte/src/minkeeper.h
|
|
index 7ac5eea..f37edef 100644
|
|
--- a/libgambatte/src/minkeeper.h
|
|
+++ b/libgambatte/src/minkeeper.h
|
|
@@ -19,7 +19,12 @@
|
|
#ifndef MINKEEPER_H
|
|
#define MINKEEPER_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include <algorithm>
|
|
+#include "loadsave.h"
|
|
|
|
namespace MinKeeperUtil {
|
|
template<int n> struct CeiledLog2 { enum { r = 1 + CeiledLog2<(n + 1) / 2>::r }; };
|
|
@@ -39,22 +44,29 @@ template<template<int> class T> struct Sum<T,0> { enum { r = 0 }; };
|
|
template<int ids>
|
|
class MinKeeper {
|
|
public:
|
|
- explicit MinKeeper(unsigned long initValue = 0xFFFFFFFF);
|
|
+ explicit MinKeeper(unsigned initValue = 0xFFFFFFFF);
|
|
int min() const { return a_[0]; }
|
|
- unsigned long minValue() const { return minValue_; }
|
|
+ unsigned minValue() const { return minValue_; }
|
|
|
|
template<int id>
|
|
- void setValue(unsigned long cnt) {
|
|
+ void setValue(unsigned cnt) {
|
|
values_[id] = cnt;
|
|
updateValue<id / 2>(*this);
|
|
}
|
|
|
|
- void setValue(int id, unsigned long cnt) {
|
|
+ void setValue(int id, unsigned cnt) {
|
|
values_[id] = cnt;
|
|
updateValueLut.call(id >> 1, *this);
|
|
}
|
|
|
|
- unsigned long value(int id) const { return values_[id]; }
|
|
+ unsigned value(int id) const { return values_[id]; }
|
|
+
|
|
+ void loadOrSave(gambatte::loadsave& state) {
|
|
+ state(values_, ids);
|
|
+ state(minValue_);
|
|
+ //updateValueLut is constant for our purposes.
|
|
+ state(a_, Sum<levels>::r);
|
|
+ }
|
|
|
|
private:
|
|
enum { levels = MinKeeperUtil::CeiledLog2<ids>::r };
|
|
@@ -101,8 +113,9 @@ private:
|
|
};
|
|
|
|
static UpdateValueLut updateValueLut;
|
|
- unsigned long values_[ids];
|
|
- unsigned long minValue_;
|
|
+
|
|
+ unsigned values_[ids];
|
|
+ unsigned minValue_;
|
|
int a_[Sum<levels>::r];
|
|
|
|
template<int id> static void updateValue(MinKeeper<ids> &m);
|
|
@@ -111,7 +124,7 @@ private:
|
|
template<int ids> typename MinKeeper<ids>::UpdateValueLut MinKeeper<ids>::updateValueLut;
|
|
|
|
template<int ids>
|
|
-MinKeeper<ids>::MinKeeper(unsigned long const initValue) {
|
|
+MinKeeper<ids>::MinKeeper(unsigned const initValue) {
|
|
std::fill(values_, values_ + ids, initValue);
|
|
|
|
for (int i = 0; i < Num<levels-1>::r; ++i) {
|
|
diff --git a/libgambatte/src/savestate.h b/libgambatte/src/savestate.h
|
|
index 52a8945..6ca7bc5 100644
|
|
--- a/libgambatte/src/savestate.h
|
|
+++ b/libgambatte/src/savestate.h
|
|
@@ -19,6 +19,11 @@
|
|
#ifndef SAVESTATE_H
|
|
#define SAVESTATE_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
+#include <ctime>
|
|
#include <cstddef>
|
|
|
|
namespace gambatte {
|
|
@@ -35,7 +40,7 @@ struct SaveState {
|
|
void set(T *p, std::size_t size) { ptr = p; size_ = size; }
|
|
|
|
friend class SaverList;
|
|
- friend void setInitState(SaveState &, bool, bool);
|
|
+ friend void setInitState(SaveState &, bool, bool, time_t);
|
|
|
|
private:
|
|
T *ptr;
|
|
@@ -43,7 +48,7 @@ struct SaveState {
|
|
};
|
|
|
|
struct CPU {
|
|
- unsigned long cycleCounter;
|
|
+ unsigned cycleCounter;
|
|
unsigned short pc;
|
|
unsigned short sp;
|
|
unsigned char a;
|
|
@@ -62,13 +67,13 @@ struct SaveState {
|
|
Ptr<unsigned char> sram;
|
|
Ptr<unsigned char> wram;
|
|
Ptr<unsigned char> ioamhram;
|
|
- unsigned long divLastUpdate;
|
|
- unsigned long timaLastUpdate;
|
|
- unsigned long tmatime;
|
|
- unsigned long nextSerialtime;
|
|
- unsigned long lastOamDmaUpdate;
|
|
- unsigned long minIntTime;
|
|
- unsigned long unhaltTime;
|
|
+ unsigned divLastUpdate;
|
|
+ unsigned timaLastUpdate;
|
|
+ unsigned tmatime;
|
|
+ unsigned nextSerialtime;
|
|
+ unsigned lastOamDmaUpdate;
|
|
+ unsigned minIntTime;
|
|
+ unsigned unhaltTime;
|
|
unsigned short rombank;
|
|
unsigned short dmaSource;
|
|
unsigned short dmaDestination;
|
|
@@ -88,8 +93,8 @@ struct SaveState {
|
|
Ptr<unsigned char> oamReaderBuf;
|
|
Ptr<bool> oamReaderSzbuf;
|
|
|
|
- unsigned long videoCycles;
|
|
- unsigned long enableDisplayM0Time;
|
|
+ unsigned videoCycles;
|
|
+ unsigned enableDisplayM0Time;
|
|
unsigned short lastM0Time;
|
|
unsigned short nextM0Irq;
|
|
unsigned short tileword;
|
|
@@ -118,24 +123,24 @@ struct SaveState {
|
|
|
|
struct SPU {
|
|
struct Duty {
|
|
- unsigned long nextPosUpdate;
|
|
+ unsigned nextPosUpdate;
|
|
unsigned char nr3;
|
|
unsigned char pos;
|
|
};
|
|
|
|
struct Env {
|
|
- unsigned long counter;
|
|
+ unsigned counter;
|
|
unsigned char volume;
|
|
};
|
|
|
|
struct LCounter {
|
|
- unsigned long counter;
|
|
+ unsigned counter;
|
|
unsigned short lengthCounter;
|
|
};
|
|
|
|
struct {
|
|
struct {
|
|
- unsigned long counter;
|
|
+ unsigned counter;
|
|
unsigned short shadow;
|
|
unsigned char nr0;
|
|
bool negging;
|
|
@@ -158,8 +163,8 @@ struct SaveState {
|
|
struct {
|
|
Ptr<unsigned char> waveRam;
|
|
LCounter lcounter;
|
|
- unsigned long waveCounter;
|
|
- unsigned long lastReadTime;
|
|
+ unsigned waveCounter;
|
|
+ unsigned lastReadTime;
|
|
unsigned char nr3;
|
|
unsigned char nr4;
|
|
unsigned char wavePos;
|
|
@@ -169,7 +174,7 @@ struct SaveState {
|
|
|
|
struct {
|
|
struct {
|
|
- unsigned long counter;
|
|
+ unsigned counter;
|
|
unsigned short reg;
|
|
} lfsr;
|
|
Env env;
|
|
@@ -178,12 +183,12 @@ struct SaveState {
|
|
bool master;
|
|
} ch4;
|
|
|
|
- unsigned long cycleCounter;
|
|
+ unsigned cycleCounter;
|
|
} spu;
|
|
|
|
struct RTC {
|
|
- unsigned long baseTime;
|
|
- unsigned long haltTime;
|
|
+ unsigned baseTime;
|
|
+ unsigned haltTime;
|
|
unsigned char dataDh;
|
|
unsigned char dataDl;
|
|
unsigned char dataH;
|
|
diff --git a/libgambatte/src/sound.cpp b/libgambatte/src/sound.cpp
|
|
index d02759c..9824f96 100644
|
|
--- a/libgambatte/src/sound.cpp
|
|
+++ b/libgambatte/src/sound.cpp
|
|
@@ -21,6 +21,10 @@
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
/*
|
|
Frame Sequencer
|
|
|
|
@@ -89,7 +93,7 @@ void PSG::loadState(SaveState const &state) {
|
|
enabled_ = state.mem.ioamhram.get()[0x126] >> 7 & 1;
|
|
}
|
|
|
|
-void PSG::accumulateChannels(unsigned long const cycles) {
|
|
+void PSG::accumulateChannels(unsigned const cycles) {
|
|
uint_least32_t *const buf = buffer_ + bufferPos_;
|
|
std::memset(buf, 0, cycles * sizeof *buf);
|
|
ch1_.update(buf, soVol_, cycles);
|
|
@@ -98,8 +102,8 @@ void PSG::accumulateChannels(unsigned long const cycles) {
|
|
ch4_.update(buf, soVol_, cycles);
|
|
}
|
|
|
|
-void PSG::generateSamples(unsigned long const cycleCounter, bool const doubleSpeed) {
|
|
- unsigned long const cycles = (cycleCounter - lastUpdate_) >> (1 + doubleSpeed);
|
|
+void PSG::generateSamples(unsigned const cycleCounter, bool const doubleSpeed) {
|
|
+ unsigned const cycles = (cycleCounter - lastUpdate_) >> (1 + doubleSpeed);
|
|
lastUpdate_ += cycles << (1 + doubleSpeed);
|
|
|
|
if (cycles)
|
|
@@ -108,12 +112,12 @@ void PSG::generateSamples(unsigned long const cycleCounter, bool const doubleSpe
|
|
bufferPos_ += cycles;
|
|
}
|
|
|
|
-void PSG::resetCounter(unsigned long newCc, unsigned long oldCc, bool doubleSpeed) {
|
|
+void PSG::resetCounter(unsigned newCc, unsigned oldCc, bool doubleSpeed) {
|
|
generateSamples(oldCc, doubleSpeed);
|
|
lastUpdate_ = newCc - (oldCc - lastUpdate_);
|
|
}
|
|
|
|
-std::size_t PSG::fillBuffer() {
|
|
+unsigned PSG::fillBuffer() {
|
|
uint_least32_t sum = rsum_;
|
|
uint_least32_t *b = buffer_;
|
|
std::size_t n = bufferPos_;
|
|
@@ -164,8 +168,8 @@ static bool isBigEndianSampleOrder() {
|
|
return u.uc[0];
|
|
}
|
|
|
|
-static unsigned long so1Mul() { return isBigEndianSampleOrder() ? 0x00000001 : 0x00010000; }
|
|
-static unsigned long so2Mul() { return isBigEndianSampleOrder() ? 0x00010000 : 0x00000001; }
|
|
+static unsigned so1Mul() { return isBigEndianSampleOrder() ? 0x00000001 : 0x00010000; }
|
|
+static unsigned so2Mul() { return isBigEndianSampleOrder() ? 0x00010000 : 0x00000001; }
|
|
|
|
void PSG::setSoVolume(unsigned nr50) {
|
|
soVol_ = ((nr50 & 0x7) + 1) * so1Mul() * 64
|
|
@@ -173,7 +177,7 @@ void PSG::setSoVolume(unsigned nr50) {
|
|
}
|
|
|
|
void PSG::mapSo(unsigned nr51) {
|
|
- unsigned long so = nr51 * so1Mul() + (nr51 >> 4) * so2Mul();
|
|
+ unsigned so = nr51 * so1Mul() + (nr51 >> 4) * so2Mul();
|
|
ch1_.setSo((so & 0x00010001) * 0xFFFF);
|
|
ch2_.setSo((so >> 1 & 0x00010001) * 0xFFFF);
|
|
ch3_.setSo((so >> 2 & 0x00010001) * 0xFFFF);
|
|
@@ -187,4 +191,17 @@ unsigned PSG::getStatus() const {
|
|
| ch4_.isActive() << 3;
|
|
}
|
|
|
|
+void PSG::loadOrSave(loadsave& state)
|
|
+{
|
|
+ ch1_.loadOrSave(state);
|
|
+ ch2_.loadOrSave(state);
|
|
+ ch3_.loadOrSave(state);
|
|
+ ch4_.loadOrSave(state);
|
|
+ state(lastUpdate_);
|
|
+ state(soVol_);
|
|
+ state(rsum_);
|
|
+ state(bufferPos_);
|
|
+ state(enabled_);
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/sound.h b/libgambatte/src/sound.h
|
|
index 6c9ce33..d7009f0 100644
|
|
--- a/libgambatte/src/sound.h
|
|
+++ b/libgambatte/src/sound.h
|
|
@@ -19,10 +19,15 @@
|
|
#ifndef SOUND_H
|
|
#define SOUND_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include "sound/channel1.h"
|
|
#include "sound/channel2.h"
|
|
#include "sound/channel3.h"
|
|
#include "sound/channel4.h"
|
|
+#include "loadsave.h"
|
|
|
|
namespace gambatte {
|
|
|
|
@@ -34,10 +39,11 @@ public:
|
|
void setStatePtrs(SaveState &state);
|
|
void saveState(SaveState &state);
|
|
void loadState(SaveState const &state);
|
|
+ void loadOrSave(loadsave& state);
|
|
|
|
- void generateSamples(unsigned long cycleCounter, bool doubleSpeed);
|
|
- void resetCounter(unsigned long newCc, unsigned long oldCc, bool doubleSpeed);
|
|
- std::size_t fillBuffer();
|
|
+ void generateSamples(unsigned cycleCounter, bool doubleSpeed);
|
|
+ void resetCounter(unsigned newCc, unsigned oldCc, bool doubleSpeed);
|
|
+ unsigned fillBuffer();
|
|
void setBuffer(uint_least32_t *buf) { buffer_ = buf; bufferPos_ = 0; }
|
|
|
|
bool isEnabled() const { return enabled_; }
|
|
@@ -77,13 +83,13 @@ private:
|
|
Channel3 ch3_;
|
|
Channel4 ch4_;
|
|
uint_least32_t *buffer_;
|
|
- std::size_t bufferPos_;
|
|
- unsigned long lastUpdate_;
|
|
- unsigned long soVol_;
|
|
+ unsigned lastUpdate_;
|
|
+ unsigned soVol_;
|
|
+ unsigned bufferPos_;
|
|
uint_least32_t rsum_;
|
|
bool enabled_;
|
|
|
|
- void accumulateChannels(unsigned long cycles);
|
|
+ void accumulateChannels(unsigned cycles);
|
|
};
|
|
|
|
}
|
|
diff --git a/libgambatte/src/sound/channel1.cpp b/libgambatte/src/sound/channel1.cpp
|
|
index 182b1a8..c517965 100644
|
|
--- a/libgambatte/src/sound/channel1.cpp
|
|
+++ b/libgambatte/src/sound/channel1.cpp
|
|
@@ -20,6 +20,10 @@
|
|
#include "../savestate.h"
|
|
#include <algorithm>
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
Channel1::SweepUnit::SweepUnit(MasterDisabler &disabler, DutyUnit &dutyUnit)
|
|
@@ -47,7 +51,7 @@ unsigned Channel1::SweepUnit::calcFreq() {
|
|
}
|
|
|
|
void Channel1::SweepUnit::event() {
|
|
- unsigned long const period = nr0_ >> 4 & 0x07;
|
|
+ unsigned const period = nr0_ >> 4 & 0x07;
|
|
|
|
if (period) {
|
|
unsigned const freq = calcFreq();
|
|
@@ -70,7 +74,7 @@ void Channel1::SweepUnit::nr0Change(unsigned newNr0) {
|
|
nr0_ = newNr0;
|
|
}
|
|
|
|
-void Channel1::SweepUnit::nr4Init(unsigned long const cc) {
|
|
+void Channel1::SweepUnit::nr4Init(unsigned const cc) {
|
|
negging_ = false;
|
|
shadow_ = dutyUnit_.freq();
|
|
|
|
@@ -168,7 +172,7 @@ void Channel1::setNr4(unsigned const data) {
|
|
setEvent();
|
|
}
|
|
|
|
-void Channel1::setSo(unsigned long soMask) {
|
|
+void Channel1::setSo(unsigned soMask) {
|
|
soMask_ = soMask;
|
|
staticOutputTest_(cycleCounter_);
|
|
setEvent();
|
|
@@ -212,17 +216,17 @@ void Channel1::loadState(SaveState const &state) {
|
|
master_ = state.spu.ch1.master;
|
|
}
|
|
|
|
-void Channel1::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cycles) {
|
|
- unsigned long const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
|
|
- unsigned long const outLow = outBase * (0 - 15ul);
|
|
- unsigned long const endCycles = cycleCounter_ + cycles;
|
|
+void Channel1::update(uint_least32_t *buf, unsigned const soBaseVol, unsigned cycles) {
|
|
+ unsigned const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
|
|
+ unsigned const outLow = outBase * (0 - 15ul);
|
|
+ unsigned const endCycles = cycleCounter_ + cycles;
|
|
|
|
for (;;) {
|
|
- unsigned long const outHigh = master_
|
|
+ unsigned const outHigh = master_
|
|
? outBase * (envelopeUnit_.getVolume() * 2 - 15ul)
|
|
: outLow;
|
|
- unsigned long const nextMajorEvent = std::min(nextEventUnit_->counter(), endCycles);
|
|
- unsigned long out = dutyUnit_.isHighState() ? outHigh : outLow;
|
|
+ unsigned const nextMajorEvent = std::min(nextEventUnit_->counter(), endCycles);
|
|
+ unsigned out = dutyUnit_.isHighState() ? outHigh : outLow;
|
|
|
|
while (dutyUnit_.counter() <= nextMajorEvent) {
|
|
*buf = out - prevOut_;
|
|
@@ -257,4 +261,25 @@ void Channel1::update(uint_least32_t *buf, unsigned long const soBaseVol, unsign
|
|
}
|
|
}
|
|
|
|
+void Channel1::loadOrSave(loadsave& state) {
|
|
+ //disableMaster has no state.
|
|
+ lengthCounter_.loadOrSave(state);
|
|
+ dutyUnit_.loadOrSave(state);
|
|
+ envelopeUnit_.loadOrSave(state);
|
|
+ sweepUnit_.loadOrSave(state);
|
|
+
|
|
+ state.startEnumeration();
|
|
+ state.enumerate<SoundUnit*>(nextEventUnit_, NULL, 0);
|
|
+ state.enumerate<SoundUnit*>(nextEventUnit_, &sweepUnit_, 1);
|
|
+ state.enumerate<SoundUnit*>(nextEventUnit_, &envelopeUnit_, 2);
|
|
+ state.enumerate<SoundUnit*>(nextEventUnit_, &lengthCounter_, 3);
|
|
+ state.endEnumeration();
|
|
+
|
|
+ state(cycleCounter_);
|
|
+ state(soMask_);
|
|
+ state(prevOut_);
|
|
+ state(nr4_);
|
|
+ state(master_);
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/sound/channel1.h b/libgambatte/src/sound/channel1.h
|
|
index b364811..b80ae24 100644
|
|
--- a/libgambatte/src/sound/channel1.h
|
|
+++ b/libgambatte/src/sound/channel1.h
|
|
@@ -19,12 +19,20 @@
|
|
#ifndef SOUND_CHANNEL1_H
|
|
#define SOUND_CHANNEL1_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
+#include "gbint.h"
|
|
+#include "master_disabler.h"
|
|
+#include "length_counter.h"
|
|
#include "duty_unit.h"
|
|
#include "envelope_unit.h"
|
|
#include "gbint.h"
|
|
#include "length_counter.h"
|
|
#include "master_disabler.h"
|
|
#include "static_output_tester.h"
|
|
+#include "loadsave.h"
|
|
|
|
namespace gambatte {
|
|
|
|
@@ -38,9 +46,10 @@ public:
|
|
void setNr2(unsigned data);
|
|
void setNr3(unsigned data);
|
|
void setNr4(unsigned data);
|
|
- void setSo(unsigned long soMask);
|
|
+ void loadOrSave(loadsave& state);
|
|
+ void setSo(unsigned soMask);
|
|
bool isActive() const { return master_; }
|
|
- void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
|
+ void update(uint_least32_t *buf, unsigned soBaseVol, unsigned cycles);
|
|
void reset();
|
|
void init(bool cgb);
|
|
void saveState(SaveState &state);
|
|
@@ -52,11 +61,18 @@ private:
|
|
SweepUnit(MasterDisabler &disabler, DutyUnit &dutyUnit);
|
|
virtual void event();
|
|
void nr0Change(unsigned newNr0);
|
|
- void nr4Init(unsigned long cycleCounter);
|
|
+ void nr4Init(unsigned cycleCounter);
|
|
void reset();
|
|
void saveState(SaveState &state) const;
|
|
void loadState(SaveState const &state);
|
|
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ loadOrSave2(state);
|
|
+ state(shadow_);
|
|
+ state(nr0_);
|
|
+ state(negging_);
|
|
+ }
|
|
+
|
|
private:
|
|
MasterDisabler &disableMaster_;
|
|
DutyUnit &dutyUnit_;
|
|
@@ -76,13 +92,14 @@ private:
|
|
EnvelopeUnit envelopeUnit_;
|
|
SweepUnit sweepUnit_;
|
|
SoundUnit *nextEventUnit_;
|
|
- unsigned long cycleCounter_;
|
|
- unsigned long soMask_;
|
|
- unsigned long prevOut_;
|
|
+ unsigned cycleCounter_;
|
|
+ unsigned soMask_;
|
|
+ unsigned prevOut_;
|
|
unsigned char nr4_;
|
|
bool master_;
|
|
|
|
void setEvent();
|
|
+
|
|
};
|
|
|
|
}
|
|
diff --git a/libgambatte/src/sound/channel2.cpp b/libgambatte/src/sound/channel2.cpp
|
|
index 7604b10..f154249 100644
|
|
--- a/libgambatte/src/sound/channel2.cpp
|
|
+++ b/libgambatte/src/sound/channel2.cpp
|
|
@@ -20,6 +20,10 @@
|
|
#include "../savestate.h"
|
|
#include <algorithm>
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
Channel2::Channel2()
|
|
@@ -76,7 +80,7 @@ void Channel2::setNr4(unsigned const data) {
|
|
setEvent();
|
|
}
|
|
|
|
-void Channel2::setSo(unsigned long soMask) {
|
|
+void Channel2::setSo(unsigned soMask) {
|
|
soMask_ = soMask;
|
|
staticOutputTest_(cycleCounter_);
|
|
setEvent();
|
|
@@ -116,17 +120,17 @@ void Channel2::loadState(SaveState const &state) {
|
|
master_ = state.spu.ch2.master;
|
|
}
|
|
|
|
-void Channel2::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cycles) {
|
|
- unsigned long const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
|
|
- unsigned long const outLow = outBase * (0 - 15ul);
|
|
- unsigned long const endCycles = cycleCounter_ + cycles;
|
|
+void Channel2::update(uint_least32_t *buf, unsigned const soBaseVol, unsigned cycles) {
|
|
+ unsigned const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
|
|
+ unsigned const outLow = outBase * (0 - 15ul);
|
|
+ unsigned const endCycles = cycleCounter_ + cycles;
|
|
|
|
for (;;) {
|
|
- unsigned long const outHigh = master_
|
|
+ unsigned const outHigh = master_
|
|
? outBase * (envelopeUnit_.getVolume() * 2 - 15ul)
|
|
: outLow;
|
|
- unsigned long const nextMajorEvent = std::min(nextEventUnit->counter(), endCycles);
|
|
- unsigned long out = dutyUnit_.isHighState() ? outHigh : outLow;
|
|
+ unsigned const nextMajorEvent = std::min(nextEventUnit->counter(), endCycles);
|
|
+ unsigned out = dutyUnit_.isHighState() ? outHigh : outLow;
|
|
|
|
while (dutyUnit_.counter() <= nextMajorEvent) {
|
|
*buf += out - prevOut_;
|
|
@@ -160,4 +164,24 @@ void Channel2::update(uint_least32_t *buf, unsigned long const soBaseVol, unsign
|
|
}
|
|
}
|
|
|
|
+void Channel2::loadOrSave(loadsave& state)
|
|
+{
|
|
+ //disableMaster has no state.
|
|
+ lengthCounter_.loadOrSave(state);
|
|
+ dutyUnit_.loadOrSave(state);
|
|
+ envelopeUnit_.loadOrSave(state);
|
|
+
|
|
+ state.startEnumeration();
|
|
+ state.enumerate<SoundUnit*>(nextEventUnit, NULL, 0);
|
|
+ state.enumerate<SoundUnit*>(nextEventUnit, &lengthCounter_, 1);
|
|
+ state.enumerate<SoundUnit*>(nextEventUnit, &envelopeUnit_, 2);
|
|
+ state.endEnumeration();
|
|
+
|
|
+ state(cycleCounter_);
|
|
+ state(soMask_);
|
|
+ state(prevOut_);
|
|
+ state(nr4_);
|
|
+ state(master_);
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/sound/channel2.h b/libgambatte/src/sound/channel2.h
|
|
index 02833aa..193c520 100644
|
|
--- a/libgambatte/src/sound/channel2.h
|
|
+++ b/libgambatte/src/sound/channel2.h
|
|
@@ -24,6 +24,11 @@
|
|
#include "gbint.h"
|
|
#include "length_counter.h"
|
|
#include "static_output_tester.h"
|
|
+#include "loadsave.h"
|
|
+
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
|
|
namespace gambatte {
|
|
|
|
@@ -36,9 +41,10 @@ public:
|
|
void setNr2(unsigned data);
|
|
void setNr3(unsigned data);
|
|
void setNr4(unsigned data);
|
|
- void setSo(unsigned long soMask);
|
|
+ void loadOrSave(loadsave& state);
|
|
+ void setSo(unsigned soMask);
|
|
bool isActive() const { return master_; }
|
|
- void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
|
+ void update(uint_least32_t *buf, unsigned soBaseVol, unsigned cycles);
|
|
void reset();
|
|
void init(bool cgb);
|
|
void saveState(SaveState &state);
|
|
@@ -53,9 +59,9 @@ private:
|
|
DutyUnit dutyUnit_;
|
|
EnvelopeUnit envelopeUnit_;
|
|
SoundUnit *nextEventUnit;
|
|
- unsigned long cycleCounter_;
|
|
- unsigned long soMask_;
|
|
- unsigned long prevOut_;
|
|
+ unsigned cycleCounter_;
|
|
+ unsigned soMask_;
|
|
+ unsigned prevOut_;
|
|
unsigned char nr4_;
|
|
bool master_;
|
|
|
|
diff --git a/libgambatte/src/sound/channel3.cpp b/libgambatte/src/sound/channel3.cpp
|
|
index a582b0c..c583949 100644
|
|
--- a/libgambatte/src/sound/channel3.cpp
|
|
+++ b/libgambatte/src/sound/channel3.cpp
|
|
@@ -21,6 +21,10 @@
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
static inline unsigned toPeriod(unsigned nr3, unsigned nr4) {
|
|
return 0x800 - ((nr4 << 8 & 0x700) | nr3);
|
|
}
|
|
@@ -79,7 +83,7 @@ void Channel3::setNr4(unsigned const data) {
|
|
}
|
|
}
|
|
|
|
-void Channel3::setSo(unsigned long soMask) {
|
|
+void Channel3::setSo(unsigned soMask) {
|
|
soMask_ = soMask;
|
|
}
|
|
|
|
@@ -127,10 +131,10 @@ void Channel3::loadState(SaveState const &state) {
|
|
setNr2(state.mem.ioamhram.get()[0x11C]);
|
|
}
|
|
|
|
-void Channel3::updateWaveCounter(unsigned long const cc) {
|
|
+void Channel3::updateWaveCounter(unsigned const cc) {
|
|
if (cc >= waveCounter_) {
|
|
unsigned const period = toPeriod(nr3_, nr4_);
|
|
- unsigned long const periods = (cc - waveCounter_) / period;
|
|
+ unsigned const periods = (cc - waveCounter_) / period;
|
|
|
|
lastReadTime_ = waveCounter_ + periods * period;
|
|
waveCounter_ = lastReadTime_ + period;
|
|
@@ -142,16 +146,16 @@ void Channel3::updateWaveCounter(unsigned long const cc) {
|
|
}
|
|
}
|
|
|
|
-void Channel3::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cycles) {
|
|
- unsigned long const outBase = nr0_/* & 0x80*/ ? soBaseVol & soMask_ : 0;
|
|
+void Channel3::update(uint_least32_t *buf, unsigned const soBaseVol, unsigned cycles) {
|
|
+ unsigned const outBase = nr0_/* & 0x80*/ ? soBaseVol & soMask_ : 0;
|
|
|
|
if (outBase && rshift_ != 4) {
|
|
- unsigned long const endCycles = cycleCounter_ + cycles;
|
|
+ unsigned const endCycles = cycleCounter_ + cycles;
|
|
|
|
for (;;) {
|
|
- unsigned long const nextMajorEvent =
|
|
+ unsigned const nextMajorEvent =
|
|
std::min(lengthCounter_.counter(), endCycles);
|
|
- unsigned long out = master_
|
|
+ unsigned out = master_
|
|
? ((sampleBuf_ >> (~wavePos_ << 2 & 4) & 0xF) >> rshift_) * 2 - 15ul
|
|
: 0 - 15ul;
|
|
out *= outBase;
|
|
@@ -184,7 +188,7 @@ void Channel3::update(uint_least32_t *buf, unsigned long const soBaseVol, unsign
|
|
break;
|
|
}
|
|
} else {
|
|
- unsigned long const out = outBase * (0 - 15ul);
|
|
+ unsigned const out = outBase * (0 - 15ul);
|
|
*buf += out - prevOut_;
|
|
prevOut_ = out;
|
|
cycleCounter_ += cycles;
|
|
@@ -208,4 +212,23 @@ void Channel3::update(uint_least32_t *buf, unsigned long const soBaseVol, unsign
|
|
}
|
|
}
|
|
|
|
+void Channel3::loadOrSave(loadsave& state) {
|
|
+ state(waveRam_, 0x10);
|
|
+ //disableMaster has no saveable state.
|
|
+ lengthCounter_.loadOrSave(state);
|
|
+ state(cycleCounter_);
|
|
+ state(soMask_);
|
|
+ state(prevOut_);
|
|
+ state(waveCounter_);
|
|
+ state(lastReadTime_);
|
|
+ state(nr0_);
|
|
+ state(nr3_);
|
|
+ state(nr4_);
|
|
+ state(wavePos_);
|
|
+ state(rshift_);
|
|
+ state(sampleBuf_);
|
|
+ state(master_);
|
|
+ state(cgb_);
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/sound/channel3.h b/libgambatte/src/sound/channel3.h
|
|
index 2a5e16a..5bd6195 100644
|
|
--- a/libgambatte/src/sound/channel3.h
|
|
+++ b/libgambatte/src/sound/channel3.h
|
|
@@ -19,8 +19,13 @@
|
|
#ifndef SOUND_CHANNEL3_H
|
|
#define SOUND_CHANNEL3_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include "gbint.h"
|
|
#include "length_counter.h"
|
|
+#include "loadsave.h"
|
|
#include "master_disabler.h"
|
|
|
|
namespace gambatte {
|
|
@@ -41,8 +46,8 @@ public:
|
|
void setNr2(unsigned data);
|
|
void setNr3(unsigned data) { nr3_ = data; }
|
|
void setNr4(unsigned data);
|
|
- void setSo(unsigned long soMask);
|
|
- void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
|
+ void setSo(unsigned soMask);
|
|
+ void update(uint_least32_t *buf, unsigned soBaseVol, unsigned cycles);
|
|
|
|
unsigned waveRamRead(unsigned index) const {
|
|
if (master_) {
|
|
@@ -66,10 +71,11 @@ public:
|
|
waveRam_[index] = data;
|
|
}
|
|
|
|
+ void loadOrSave(loadsave& state);
|
|
private:
|
|
class Ch3MasterDisabler : public MasterDisabler {
|
|
public:
|
|
- Ch3MasterDisabler(bool &m, unsigned long &wC) : MasterDisabler(m), waveCounter_(wC) {}
|
|
+ Ch3MasterDisabler(bool &m, unsigned &wC) : MasterDisabler(m), waveCounter_(wC) {}
|
|
|
|
virtual void operator()() {
|
|
MasterDisabler::operator()();
|
|
@@ -77,17 +83,17 @@ private:
|
|
}
|
|
|
|
private:
|
|
- unsigned long &waveCounter_;
|
|
+ unsigned &waveCounter_;
|
|
};
|
|
|
|
unsigned char waveRam_[0x10];
|
|
Ch3MasterDisabler disableMaster_;
|
|
LengthCounter lengthCounter_;
|
|
- unsigned long cycleCounter_;
|
|
- unsigned long soMask_;
|
|
- unsigned long prevOut_;
|
|
- unsigned long waveCounter_;
|
|
- unsigned long lastReadTime_;
|
|
+ unsigned cycleCounter_;
|
|
+ unsigned soMask_;
|
|
+ unsigned prevOut_;
|
|
+ unsigned waveCounter_;
|
|
+ unsigned lastReadTime_;
|
|
unsigned char nr0_;
|
|
unsigned char nr3_;
|
|
unsigned char nr4_;
|
|
@@ -97,7 +103,7 @@ private:
|
|
bool master_;
|
|
bool cgb_;
|
|
|
|
- void updateWaveCounter(unsigned long cc);
|
|
+ void updateWaveCounter(unsigned cc);
|
|
};
|
|
|
|
}
|
|
diff --git a/libgambatte/src/sound/channel4.cpp b/libgambatte/src/sound/channel4.cpp
|
|
index 7c4bc18..bc0a312 100644
|
|
--- a/libgambatte/src/sound/channel4.cpp
|
|
+++ b/libgambatte/src/sound/channel4.cpp
|
|
@@ -20,7 +20,11 @@
|
|
#include "../savestate.h"
|
|
#include <algorithm>
|
|
|
|
-static unsigned long toPeriod(unsigned const nr3) {
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
+static unsigned toPeriod(unsigned const nr3) {
|
|
unsigned s = (nr3 >> 4) + 3;
|
|
unsigned r = nr3 & 7;
|
|
|
|
@@ -42,10 +46,10 @@ Channel4::Lfsr::Lfsr()
|
|
{
|
|
}
|
|
|
|
-void Channel4::Lfsr::updateBackupCounter(unsigned long const cc) {
|
|
+void Channel4::Lfsr::updateBackupCounter(unsigned const cc) {
|
|
if (backupCounter_ <= cc) {
|
|
- unsigned long const period = toPeriod(nr3_);
|
|
- unsigned long periods = (cc - backupCounter_) / period + 1;
|
|
+ unsigned const period = toPeriod(nr3_);
|
|
+ unsigned periods = (cc - backupCounter_) / period + 1;
|
|
backupCounter_ += periods * period;
|
|
|
|
if (master_ && nr3_ < 0xE0) {
|
|
@@ -70,7 +74,7 @@ void Channel4::Lfsr::updateBackupCounter(unsigned long const cc) {
|
|
}
|
|
}
|
|
|
|
-void Channel4::Lfsr::reviveCounter(unsigned long cc) {
|
|
+void Channel4::Lfsr::reviveCounter(unsigned cc) {
|
|
updateBackupCounter(cc);
|
|
counter_ = backupCounter_;
|
|
}
|
|
@@ -89,12 +93,12 @@ inline void Channel4::Lfsr::event() {
|
|
backupCounter_ = counter_;
|
|
}
|
|
|
|
-void Channel4::Lfsr::nr3Change(unsigned newNr3, unsigned long cc) {
|
|
+void Channel4::Lfsr::nr3Change(unsigned newNr3, unsigned cc) {
|
|
updateBackupCounter(cc);
|
|
nr3_ = newNr3;
|
|
}
|
|
|
|
-void Channel4::Lfsr::nr4Init(unsigned long cc) {
|
|
+void Channel4::Lfsr::nr4Init(unsigned cc) {
|
|
disableMaster();
|
|
updateBackupCounter(cc);
|
|
master_ = true;
|
|
@@ -102,19 +106,19 @@ void Channel4::Lfsr::nr4Init(unsigned long cc) {
|
|
counter_ = backupCounter_;
|
|
}
|
|
|
|
-void Channel4::Lfsr::reset(unsigned long cc) {
|
|
+void Channel4::Lfsr::reset(unsigned cc) {
|
|
nr3_ = 0;
|
|
disableMaster();
|
|
backupCounter_ = cc + toPeriod(nr3_);
|
|
}
|
|
|
|
-void Channel4::Lfsr::resetCounters(unsigned long oldCc) {
|
|
+void Channel4::Lfsr::resetCounters(unsigned oldCc) {
|
|
updateBackupCounter(oldCc);
|
|
backupCounter_ -= counter_max;
|
|
SoundUnit::resetCounters(oldCc);
|
|
}
|
|
|
|
-void Channel4::Lfsr::saveState(SaveState &state, unsigned long cc) {
|
|
+void Channel4::Lfsr::saveState(SaveState &state, unsigned cc) {
|
|
updateBackupCounter(cc);
|
|
state.spu.ch4.lfsr.counter = backupCounter_;
|
|
state.spu.ch4.lfsr.reg = reg_;
|
|
@@ -179,7 +183,7 @@ void Channel4::setNr4(unsigned const data) {
|
|
setEvent();
|
|
}
|
|
|
|
-void Channel4::setSo(unsigned long soMask) {
|
|
+void Channel4::setSo(unsigned soMask) {
|
|
soMask_ = soMask;
|
|
staticOutputTest_(cycleCounter_);
|
|
setEvent();
|
|
@@ -218,15 +222,15 @@ void Channel4::loadState(SaveState const &state) {
|
|
master_ = state.spu.ch4.master;
|
|
}
|
|
|
|
-void Channel4::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cycles) {
|
|
- unsigned long const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
|
|
- unsigned long const outLow = outBase * (0 - 15ul);
|
|
- unsigned long const endCycles = cycleCounter_ + cycles;
|
|
+void Channel4::update(uint_least32_t *buf, unsigned const soBaseVol, unsigned cycles) {
|
|
+ unsigned const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
|
|
+ unsigned const outLow = outBase * (0 - 15ul);
|
|
+ unsigned const endCycles = cycleCounter_ + cycles;
|
|
|
|
for (;;) {
|
|
- unsigned long const outHigh = outBase * (envelopeUnit_.getVolume() * 2 - 15ul);
|
|
- unsigned long const nextMajorEvent = std::min(nextEventUnit_->counter(), endCycles);
|
|
- unsigned long out = lfsr_.isHighState() ? outHigh : outLow;
|
|
+ unsigned const outHigh = outBase * (envelopeUnit_.getVolume() * 2 - 15ul);
|
|
+ unsigned const nextMajorEvent = std::min(nextEventUnit_->counter(), endCycles);
|
|
+ unsigned out = lfsr_.isHighState() ? outHigh : outLow;
|
|
|
|
while (lfsr_.counter() <= nextMajorEvent) {
|
|
*buf += out - prevOut_;
|
|
@@ -260,4 +264,23 @@ void Channel4::update(uint_least32_t *buf, unsigned long const soBaseVol, unsign
|
|
}
|
|
}
|
|
|
|
+void Channel4::loadOrSave(loadsave& state) {
|
|
+ //DisableMaster has no state.
|
|
+ lengthCounter_.loadOrSave(state);
|
|
+ envelopeUnit_.loadOrSave(state);
|
|
+ lfsr_.loadOrSave(state);
|
|
+
|
|
+ state.startEnumeration();
|
|
+ state.enumerate<SoundUnit*>(nextEventUnit_, NULL, 0);
|
|
+ state.enumerate<SoundUnit*>(nextEventUnit_, &lengthCounter_, 1);
|
|
+ state.enumerate<SoundUnit*>(nextEventUnit_, &envelopeUnit_, 2);
|
|
+ state.endEnumeration();
|
|
+
|
|
+ state(cycleCounter_);
|
|
+ state(soMask_);
|
|
+ state(prevOut_);
|
|
+ state(nr4_);
|
|
+ state(master_);
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/sound/channel4.h b/libgambatte/src/sound/channel4.h
|
|
index 9070b59..cb18afa 100644
|
|
--- a/libgambatte/src/sound/channel4.h
|
|
+++ b/libgambatte/src/sound/channel4.h
|
|
@@ -24,6 +24,11 @@
|
|
#include "length_counter.h"
|
|
#include "master_disabler.h"
|
|
#include "static_output_tester.h"
|
|
+#include "loadsave.h"
|
|
+
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
|
|
namespace gambatte {
|
|
|
|
@@ -36,9 +41,10 @@ public:
|
|
void setNr2(unsigned data);
|
|
void setNr3(unsigned data) { lfsr_.nr3Change(data, cycleCounter_); }
|
|
void setNr4(unsigned data);
|
|
- void setSo(unsigned long soMask);
|
|
+ void loadOrSave(loadsave& state);
|
|
+ void setSo(unsigned soMask);
|
|
bool isActive() const { return master_; }
|
|
- void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
|
|
+ void update(uint_least32_t *buf, unsigned soBaseVol, unsigned cycles);
|
|
void reset();
|
|
void init(bool cgb);
|
|
void saveState(SaveState &state);
|
|
@@ -49,24 +55,31 @@ private:
|
|
public:
|
|
Lfsr();
|
|
virtual void event();
|
|
- virtual void resetCounters(unsigned long oldCc);
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ loadOrSave2(state);
|
|
+ state(backupCounter_);
|
|
+ state(reg_);
|
|
+ state(nr3_);
|
|
+ state(master_);
|
|
+ }
|
|
+ virtual void resetCounters(unsigned oldCc);
|
|
bool isHighState() const { return ~reg_ & 1; }
|
|
- void nr3Change(unsigned newNr3, unsigned long cc);
|
|
- void nr4Init(unsigned long cc);
|
|
- void reset(unsigned long cc);
|
|
- void saveState(SaveState &state, unsigned long cc);
|
|
+ void nr3Change(unsigned newNr3, unsigned cc);
|
|
+ void nr4Init(unsigned cc);
|
|
+ void reset(unsigned cc);
|
|
+ void saveState(SaveState &state, unsigned cc);
|
|
void loadState(SaveState const &state);
|
|
void disableMaster() { killCounter(); master_ = false; reg_ = 0x7FFF; }
|
|
void killCounter() { counter_ = counter_disabled; }
|
|
- void reviveCounter(unsigned long cc);
|
|
+ void reviveCounter(unsigned cc);
|
|
|
|
private:
|
|
- unsigned long backupCounter_;
|
|
+ unsigned backupCounter_;
|
|
unsigned short reg_;
|
|
unsigned char nr3_;
|
|
bool master_;
|
|
|
|
- void updateBackupCounter(unsigned long cc);
|
|
+ void updateBackupCounter(unsigned cc);
|
|
};
|
|
|
|
class Ch4MasterDisabler : public MasterDisabler {
|
|
@@ -86,9 +99,9 @@ private:
|
|
EnvelopeUnit envelopeUnit_;
|
|
Lfsr lfsr_;
|
|
SoundUnit *nextEventUnit_;
|
|
- unsigned long cycleCounter_;
|
|
- unsigned long soMask_;
|
|
- unsigned long prevOut_;
|
|
+ unsigned cycleCounter_;
|
|
+ unsigned soMask_;
|
|
+ unsigned prevOut_;
|
|
unsigned char nr4_;
|
|
bool master_;
|
|
|
|
diff --git a/libgambatte/src/sound/duty_unit.cpp b/libgambatte/src/sound/duty_unit.cpp
|
|
index df37b66..4258508 100644
|
|
--- a/libgambatte/src/sound/duty_unit.cpp
|
|
+++ b/libgambatte/src/sound/duty_unit.cpp
|
|
@@ -19,6 +19,10 @@
|
|
#include "duty_unit.h"
|
|
#include <algorithm>
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
static inline bool toOutState(unsigned duty, unsigned pos) {
|
|
static unsigned char const duties[4] = { 0x80, 0x81, 0xE1, 0x7E };
|
|
return duties[duty] >> pos & 1;
|
|
@@ -40,9 +44,9 @@ DutyUnit::DutyUnit()
|
|
{
|
|
}
|
|
|
|
-void DutyUnit::updatePos(unsigned long const cc) {
|
|
+void DutyUnit::updatePos(unsigned const cc) {
|
|
if (cc >= nextPosUpdate_) {
|
|
- unsigned long const inc = (cc - nextPosUpdate_) / period_ + 1;
|
|
+ unsigned const inc = (cc - nextPosUpdate_) / period_ + 1;
|
|
nextPosUpdate_ += period_ * inc;
|
|
pos_ += inc;
|
|
pos_ &= 7;
|
|
@@ -68,7 +72,7 @@ void DutyUnit::setCounter() {
|
|
counter_ = counter_disabled;
|
|
}
|
|
|
|
-void DutyUnit::setFreq(unsigned newFreq, unsigned long cc) {
|
|
+void DutyUnit::setFreq(unsigned newFreq, unsigned cc) {
|
|
updatePos(cc);
|
|
period_ = toPeriod(newFreq);
|
|
setCounter();
|
|
@@ -86,17 +90,17 @@ void DutyUnit::event() {
|
|
counter_ += inc;
|
|
}
|
|
|
|
-void DutyUnit::nr1Change(unsigned newNr1, unsigned long cc) {
|
|
+void DutyUnit::nr1Change(unsigned newNr1, unsigned cc) {
|
|
updatePos(cc);
|
|
setDuty(newNr1);
|
|
setCounter();
|
|
}
|
|
|
|
-void DutyUnit::nr3Change(unsigned newNr3, unsigned long cc) {
|
|
+void DutyUnit::nr3Change(unsigned newNr3, unsigned cc) {
|
|
setFreq((freq() & 0x700) | newNr3, cc);
|
|
}
|
|
|
|
-void DutyUnit::nr4Change(unsigned const newNr4, unsigned long const cc) {
|
|
+void DutyUnit::nr4Change(unsigned const newNr4, unsigned const cc) {
|
|
setFreq((newNr4 << 8 & 0x700) | (freq() & 0xFF), cc);
|
|
|
|
if (newNr4 & 0x80) {
|
|
@@ -112,7 +116,7 @@ void DutyUnit::reset() {
|
|
setCounter();
|
|
}
|
|
|
|
-void DutyUnit::saveState(SaveState::SPU::Duty &dstate, unsigned long const cc) {
|
|
+void DutyUnit::saveState(SaveState::SPU::Duty &dstate, unsigned const cc) {
|
|
updatePos(cc);
|
|
dstate.nextPosUpdate = nextPosUpdate_;
|
|
dstate.nr3 = freq() & 0xFF;
|
|
@@ -120,7 +124,7 @@ void DutyUnit::saveState(SaveState::SPU::Duty &dstate, unsigned long const cc) {
|
|
}
|
|
|
|
void DutyUnit::loadState(const SaveState::SPU::Duty &dstate,
|
|
- unsigned const nr1, unsigned const nr4, unsigned long const cc) {
|
|
+ unsigned const nr1, unsigned const nr4, unsigned const cc) {
|
|
nextPosUpdate_ = std::max(dstate.nextPosUpdate, cc);
|
|
pos_ = dstate.pos & 7;
|
|
setDuty(nr1);
|
|
@@ -129,7 +133,7 @@ void DutyUnit::loadState(const SaveState::SPU::Duty &dstate,
|
|
setCounter();
|
|
}
|
|
|
|
-void DutyUnit::resetCounters(unsigned long const oldCc) {
|
|
+void DutyUnit::resetCounters(unsigned const oldCc) {
|
|
if (nextPosUpdate_ == counter_disabled)
|
|
return;
|
|
|
|
@@ -143,11 +147,21 @@ void DutyUnit::killCounter() {
|
|
setCounter();
|
|
}
|
|
|
|
-void DutyUnit::reviveCounter(unsigned long const cc) {
|
|
+void DutyUnit::reviveCounter(unsigned const cc) {
|
|
updatePos(cc);
|
|
high_ = toOutState(duty_, pos_);
|
|
enableEvents_ = true;
|
|
setCounter();
|
|
}
|
|
|
|
+void DutyUnit::loadOrSave(loadsave& state) {
|
|
+ loadOrSave2(state);
|
|
+ state(nextPosUpdate_);
|
|
+ state(period_);
|
|
+ state(pos_);
|
|
+ state(duty_);
|
|
+ state(high_);
|
|
+ state(enableEvents_);
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/sound/duty_unit.h b/libgambatte/src/sound/duty_unit.h
|
|
index 7539c1b..a3a565c 100644
|
|
--- a/libgambatte/src/sound/duty_unit.h
|
|
+++ b/libgambatte/src/sound/duty_unit.h
|
|
@@ -19,9 +19,14 @@
|
|
#ifndef DUTY_UNIT_H
|
|
#define DUTY_UNIT_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include "sound_unit.h"
|
|
#include "master_disabler.h"
|
|
#include "../savestate.h"
|
|
+#include "../loadsave.h"
|
|
|
|
namespace gambatte {
|
|
|
|
@@ -29,23 +34,25 @@ class DutyUnit : public SoundUnit {
|
|
public:
|
|
DutyUnit();
|
|
virtual void event();
|
|
- virtual void resetCounters(unsigned long oldCc);
|
|
+ virtual void resetCounters(unsigned oldCc);
|
|
bool isHighState() const { return high_; }
|
|
- void nr1Change(unsigned newNr1, unsigned long cc);
|
|
- void nr3Change(unsigned newNr3, unsigned long cc);
|
|
- void nr4Change(unsigned newNr4, unsigned long cc);
|
|
+ void nr1Change(unsigned newNr1, unsigned cc);
|
|
+ void nr3Change(unsigned newNr3, unsigned cc);
|
|
+ void nr4Change(unsigned newNr4, unsigned cc);
|
|
void reset();
|
|
- void saveState(SaveState::SPU::Duty &dstate, unsigned long cc);
|
|
- void loadState(SaveState::SPU::Duty const &dstate, unsigned nr1, unsigned nr4, unsigned long cc);
|
|
+ void saveState(SaveState::SPU::Duty &dstate, unsigned cc);
|
|
+ void loadState(SaveState::SPU::Duty const &dstate, unsigned nr1, unsigned nr4, unsigned cc);
|
|
void killCounter();
|
|
- void reviveCounter(unsigned long cc);
|
|
+ void reviveCounter(unsigned cc);
|
|
+
|
|
+ void loadOrSave(loadsave& state);
|
|
|
|
//intended for use by SweepUnit only.
|
|
unsigned freq() const { return 2048 - (period_ >> 1); }
|
|
- void setFreq(unsigned newFreq, unsigned long cc);
|
|
+ void setFreq(unsigned newFreq, unsigned cc);
|
|
|
|
private:
|
|
- unsigned long nextPosUpdate_;
|
|
+ unsigned nextPosUpdate_;
|
|
unsigned short period_;
|
|
unsigned char pos_;
|
|
unsigned char duty_;
|
|
@@ -54,7 +61,7 @@ private:
|
|
|
|
void setCounter();
|
|
void setDuty(unsigned nr1);
|
|
- void updatePos(unsigned long cc);
|
|
+ void updatePos(unsigned cc);
|
|
};
|
|
|
|
class DutyMasterDisabler : public MasterDisabler {
|
|
diff --git a/libgambatte/src/sound/envelope_unit.cpp b/libgambatte/src/sound/envelope_unit.cpp
|
|
index 248b6b6..67b563c 100644
|
|
--- a/libgambatte/src/sound/envelope_unit.cpp
|
|
+++ b/libgambatte/src/sound/envelope_unit.cpp
|
|
@@ -19,6 +19,10 @@
|
|
#include "envelope_unit.h"
|
|
#include <algorithm>
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
EnvelopeUnit::VolOnOffEvent EnvelopeUnit::nullEvent_;
|
|
@@ -39,14 +43,14 @@ void EnvelopeUnit::saveState(SaveState::SPU::Env &estate) const {
|
|
estate.volume = volume_;
|
|
}
|
|
|
|
-void EnvelopeUnit::loadState(SaveState::SPU::Env const &estate, unsigned nr2, unsigned long cc) {
|
|
+void EnvelopeUnit::loadState(SaveState::SPU::Env const &estate, unsigned nr2, unsigned cc) {
|
|
counter_ = std::max(estate.counter, cc);
|
|
volume_ = estate.volume;
|
|
nr2_ = nr2;
|
|
}
|
|
|
|
void EnvelopeUnit::event() {
|
|
- unsigned long const period = nr2_ & 7;
|
|
+ unsigned const period = nr2_ & 7;
|
|
|
|
if (period) {
|
|
unsigned newVol = volume_;
|
|
@@ -81,9 +85,9 @@ bool EnvelopeUnit::nr2Change(unsigned const newNr2) {
|
|
return !(newNr2 & 0xF8);
|
|
}
|
|
|
|
-bool EnvelopeUnit::nr4Init(unsigned long const cc) {
|
|
+bool EnvelopeUnit::nr4Init(unsigned const cc) {
|
|
{
|
|
- unsigned long period = nr2_ & 7;
|
|
+ unsigned period = nr2_ & 7;
|
|
|
|
if (!period)
|
|
period = 8;
|
|
@@ -98,4 +102,11 @@ bool EnvelopeUnit::nr4Init(unsigned long const cc) {
|
|
return !(nr2_ & 0xF8);
|
|
}
|
|
|
|
+void EnvelopeUnit::loadOrSave(loadsave& state)
|
|
+{
|
|
+ loadOrSave2(state);
|
|
+ state(nr2_);
|
|
+ state(volume_);
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/sound/envelope_unit.h b/libgambatte/src/sound/envelope_unit.h
|
|
index e1d092d..133667d 100644
|
|
--- a/libgambatte/src/sound/envelope_unit.h
|
|
+++ b/libgambatte/src/sound/envelope_unit.h
|
|
@@ -19,8 +19,13 @@
|
|
#ifndef ENVELOPE_UNIT_H
|
|
#define ENVELOPE_UNIT_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include "sound_unit.h"
|
|
#include "../savestate.h"
|
|
+#include "../loadsave.h"
|
|
|
|
namespace gambatte {
|
|
|
|
@@ -28,7 +33,7 @@ class EnvelopeUnit : public SoundUnit {
|
|
public:
|
|
struct VolOnOffEvent {
|
|
virtual ~VolOnOffEvent() {}
|
|
- virtual void operator()(unsigned long /*cc*/) {}
|
|
+ virtual void operator()(unsigned /*cc*/) {}
|
|
};
|
|
|
|
explicit EnvelopeUnit(VolOnOffEvent &volOnOffEvent = nullEvent_);
|
|
@@ -36,10 +41,11 @@ public:
|
|
bool dacIsOn() const { return nr2_ & 0xF8; }
|
|
unsigned getVolume() const { return volume_; }
|
|
bool nr2Change(unsigned newNr2);
|
|
- bool nr4Init(unsigned long cycleCounter);
|
|
+ bool nr4Init(unsigned cycleCounter);
|
|
void reset();
|
|
void saveState(SaveState::SPU::Env &estate) const;
|
|
- void loadState(SaveState::SPU::Env const &estate, unsigned nr2, unsigned long cc);
|
|
+ void loadOrSave(loadsave& state);
|
|
+ void loadState(SaveState::SPU::Env const &estate, unsigned nr2, unsigned cc);
|
|
|
|
private:
|
|
static VolOnOffEvent nullEvent_;
|
|
diff --git a/libgambatte/src/sound/length_counter.cpp b/libgambatte/src/sound/length_counter.cpp
|
|
index e4dadcb..9aa3422 100644
|
|
--- a/libgambatte/src/sound/length_counter.cpp
|
|
+++ b/libgambatte/src/sound/length_counter.cpp
|
|
@@ -20,6 +20,10 @@
|
|
#include "master_disabler.h"
|
|
#include <algorithm>
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
LengthCounter::LengthCounter(MasterDisabler &disabler, unsigned const mask)
|
|
@@ -37,14 +41,14 @@ void LengthCounter::event() {
|
|
disableMaster_();
|
|
}
|
|
|
|
-void LengthCounter::nr1Change(unsigned const newNr1, unsigned const nr4, unsigned long const cc) {
|
|
+void LengthCounter::nr1Change(unsigned const newNr1, unsigned const nr4, unsigned const cc) {
|
|
lengthCounter_ = (~newNr1 & lengthMask_) + 1;
|
|
counter_ = nr4 & 0x40
|
|
? ((cc >> 13) + lengthCounter_) << 13
|
|
- : static_cast<unsigned long>(counter_disabled);
|
|
+ : static_cast<unsigned>(counter_disabled);
|
|
}
|
|
|
|
-void LengthCounter::nr4Change(unsigned const oldNr4, unsigned const newNr4, unsigned long const cc) {
|
|
+void LengthCounter::nr4Change(unsigned const oldNr4, unsigned const newNr4, unsigned const cc) {
|
|
if (counter_ != counter_disabled)
|
|
lengthCounter_ = (counter_ >> 13) - (cc >> 13);
|
|
|
|
@@ -79,9 +83,16 @@ void LengthCounter::saveState(SaveState::SPU::LCounter &lstate) const {
|
|
lstate.lengthCounter = lengthCounter_;
|
|
}
|
|
|
|
-void LengthCounter::loadState(SaveState::SPU::LCounter const &lstate, unsigned long const cc) {
|
|
+void LengthCounter::loadState(SaveState::SPU::LCounter const &lstate, unsigned const cc) {
|
|
counter_ = std::max(lstate.counter, cc);
|
|
lengthCounter_ = lstate.lengthCounter;
|
|
}
|
|
|
|
+void LengthCounter::loadOrSave(loadsave& state)
|
|
+{
|
|
+ loadOrSave2(state);
|
|
+ state(lengthCounter_);
|
|
+ state(cgb_);
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/sound/length_counter.h b/libgambatte/src/sound/length_counter.h
|
|
index 47f0c96..3311802 100644
|
|
--- a/libgambatte/src/sound/length_counter.h
|
|
+++ b/libgambatte/src/sound/length_counter.h
|
|
@@ -19,8 +19,13 @@
|
|
#ifndef LENGTH_COUNTER_H
|
|
#define LENGTH_COUNTER_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include "sound_unit.h"
|
|
#include "../savestate.h"
|
|
+#include "../loadsave.h"
|
|
|
|
namespace gambatte {
|
|
|
|
@@ -29,12 +34,13 @@ class MasterDisabler;
|
|
class LengthCounter : public SoundUnit {
|
|
public:
|
|
LengthCounter(MasterDisabler &disabler, unsigned lengthMask);
|
|
+ void loadOrSave(loadsave& state);
|
|
virtual void event();
|
|
- void nr1Change(unsigned newNr1, unsigned nr4, unsigned long cc);
|
|
- void nr4Change(unsigned oldNr4, unsigned newNr4, unsigned long cc);
|
|
+ void nr1Change(unsigned newNr1, unsigned nr4, unsigned cc);
|
|
+ void nr4Change(unsigned oldNr4, unsigned newNr4, unsigned cc);
|
|
void init(bool cgb);
|
|
void saveState(SaveState::SPU::LCounter &lstate) const;
|
|
- void loadState(SaveState::SPU::LCounter const &lstate, unsigned long cc);
|
|
+ void loadState(SaveState::SPU::LCounter const &lstate, unsigned cc);
|
|
|
|
private:
|
|
MasterDisabler &disableMaster_;
|
|
diff --git a/libgambatte/src/sound/sound_unit.h b/libgambatte/src/sound/sound_unit.h
|
|
index a504ce7..6c503d6 100644
|
|
--- a/libgambatte/src/sound/sound_unit.h
|
|
+++ b/libgambatte/src/sound/sound_unit.h
|
|
@@ -19,6 +19,12 @@
|
|
#ifndef SOUND_UNIT_H
|
|
#define SOUND_UNIT_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
+#include "../loadsave.h"
|
|
+
|
|
namespace gambatte {
|
|
|
|
class SoundUnit {
|
|
@@ -27,17 +33,20 @@ public:
|
|
|
|
virtual ~SoundUnit() {}
|
|
virtual void event() = 0;
|
|
+ void loadOrSave2(loadsave& state) {
|
|
+ state(counter_);
|
|
+ }
|
|
|
|
- virtual void resetCounters(unsigned long /*oldCc*/) {
|
|
+ virtual void resetCounters(unsigned /*oldCc*/) {
|
|
if (counter_ != counter_disabled)
|
|
counter_ -= counter_max;
|
|
}
|
|
|
|
- unsigned long counter() const { return counter_; }
|
|
+ unsigned counter() const { return counter_; }
|
|
|
|
protected:
|
|
SoundUnit() : counter_(counter_disabled) {}
|
|
- unsigned long counter_;
|
|
+ unsigned counter_;
|
|
};
|
|
|
|
}
|
|
diff --git a/libgambatte/src/sound/static_output_tester.h b/libgambatte/src/sound/static_output_tester.h
|
|
index 84a1ec8..00c2004 100644
|
|
--- a/libgambatte/src/sound/static_output_tester.h
|
|
+++ b/libgambatte/src/sound/static_output_tester.h
|
|
@@ -19,6 +19,10 @@
|
|
#ifndef STATIC_OUTPUT_TESTER_H
|
|
#define STATIC_OUTPUT_TESTER_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include "envelope_unit.h"
|
|
|
|
namespace gambatte {
|
|
@@ -27,7 +31,7 @@ template<class Channel, class Unit>
|
|
class StaticOutputTester : public EnvelopeUnit::VolOnOffEvent {
|
|
public:
|
|
StaticOutputTester(Channel const &ch, Unit &unit) : ch_(ch), unit_(unit) {}
|
|
- void operator()(unsigned long cc);
|
|
+ void operator()(unsigned cc);
|
|
|
|
private:
|
|
Channel const &ch_;
|
|
@@ -35,7 +39,7 @@ private:
|
|
};
|
|
|
|
template<class Channel, class Unit>
|
|
-void StaticOutputTester<Channel, Unit>::operator()(unsigned long cc) {
|
|
+void StaticOutputTester<Channel, Unit>::operator()(unsigned cc) {
|
|
if (ch_.soMask_ && ch_.master_ && ch_.envelopeUnit_.getVolume())
|
|
unit_.reviveCounter(cc);
|
|
else
|
|
diff --git a/libgambatte/src/state_osd_elements.cpp b/libgambatte/src/state_osd_elements.cpp
|
|
index 361ce1f..e74bca8 100644
|
|
--- a/libgambatte/src/state_osd_elements.cpp
|
|
+++ b/libgambatte/src/state_osd_elements.cpp
|
|
@@ -23,6 +23,10 @@
|
|
#include <fstream>
|
|
#include <cstring>
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace {
|
|
|
|
using namespace gambatte;
|
|
@@ -72,7 +76,7 @@ ShadedTextOsdElment::ShadedTextOsdElment(unsigned width, const char *txt)
|
|
print(pixels + 1 * w() + 1, w(), 0xE0E0E0ul, txt);*/
|
|
|
|
bitmapfont::print(pixels.get() , w(), ShadeFill(), txt);
|
|
- bitmapfont::print(pixels.get() + 1 * w() + 1, w(), 0xE0E0E0ul , txt);
|
|
+ bitmapfont::print(pixels.get() + 1 * w() + 1, w(), 0xE0E0E0u , txt);
|
|
}
|
|
|
|
const uint_least32_t* ShadedTextOsdElment::update() {
|
|
@@ -132,7 +136,7 @@ SaveStateOsdElement::SaveStateOsdElement(const std::string &fileName, unsigned s
|
|
using namespace bitmapfont;
|
|
static const char txt[] = { E,m,p,t,bitmapfont::y,0 };
|
|
print(pixels + 3 + (StateSaver::ss_height / 2 - bitmapfont::HEIGHT / 2) * StateSaver::ss_width,
|
|
- StateSaver::ss_width, 0x808080ul, txt);
|
|
+ StateSaver::ss_width, 0x808080u, txt);
|
|
}
|
|
}
|
|
|
|
diff --git a/libgambatte/src/statesaver.cpp b/libgambatte/src/statesaver.cpp
|
|
index 198ef05..a1dcb55 100644
|
|
--- a/libgambatte/src/statesaver.cpp
|
|
+++ b/libgambatte/src/statesaver.cpp
|
|
@@ -77,7 +77,7 @@ static void write(std::ofstream &file, unsigned short data) {
|
|
file.put(data & 0xFF);
|
|
}
|
|
|
|
-static void write(std::ofstream &file, unsigned long data) {
|
|
+static void write(std::ofstream &file, unsigned data) {
|
|
static char const inf[] = { 0x00, 0x00, 0x04 };
|
|
file.write(inf, sizeof inf);
|
|
put32(file, data);
|
|
@@ -130,7 +130,7 @@ static inline void read(std::ifstream &file, unsigned short &data) {
|
|
data = read(file) & 0xFFFF;
|
|
}
|
|
|
|
-static inline void read(std::ifstream &file, unsigned long &data) {
|
|
+static inline void read(std::ifstream &file, unsigned &data) {
|
|
data = read(file);
|
|
}
|
|
|
|
diff --git a/libgambatte/src/statesaver.h b/libgambatte/src/statesaver.h
|
|
index e62f1ef..89662f6 100644
|
|
--- a/libgambatte/src/statesaver.h
|
|
+++ b/libgambatte/src/statesaver.h
|
|
@@ -19,9 +19,14 @@
|
|
#ifndef STATESAVER_H
|
|
#define STATESAVER_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include "gbint.h"
|
|
#include <cstddef>
|
|
#include <string>
|
|
+#include <vector>
|
|
|
|
namespace gambatte {
|
|
|
|
diff --git a/libgambatte/src/tima.cpp b/libgambatte/src/tima.cpp
|
|
index 649f24b..bb056ac 100644
|
|
--- a/libgambatte/src/tima.cpp
|
|
+++ b/libgambatte/src/tima.cpp
|
|
@@ -19,6 +19,10 @@
|
|
#include "tima.h"
|
|
#include "savestate.h"
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
static unsigned char const timaClock[4] = { 10, 4, 6, 8 };
|
|
|
|
namespace gambatte {
|
|
@@ -44,7 +48,7 @@ void Tima::loadState(SaveState const &state, TimaInterruptRequester timaIrq) {
|
|
tma_ = state.mem.ioamhram.get()[0x106];
|
|
tac_ = state.mem.ioamhram.get()[0x107];
|
|
|
|
- unsigned long nextIrqEventTime = disabled_time;
|
|
+ unsigned nextIrqEventTime = disabled_time;
|
|
if (tac_ & 4) {
|
|
nextIrqEventTime = tmatime_ != disabled_time && tmatime_ > state.cpu.cycleCounter
|
|
? tmatime_
|
|
@@ -54,12 +58,12 @@ void Tima::loadState(SaveState const &state, TimaInterruptRequester timaIrq) {
|
|
timaIrq.setNextIrqEventTime(nextIrqEventTime);
|
|
}
|
|
|
|
-void Tima::resetCc(unsigned long const oldCc, unsigned long const newCc, TimaInterruptRequester timaIrq) {
|
|
+void Tima::resetCc(unsigned const oldCc, unsigned const newCc, TimaInterruptRequester timaIrq) {
|
|
if (tac_ & 0x04) {
|
|
updateIrq(oldCc, timaIrq);
|
|
updateTima(oldCc);
|
|
|
|
- unsigned long const dec = oldCc - newCc;
|
|
+ unsigned const dec = oldCc - newCc;
|
|
lastUpdate_ -= dec;
|
|
timaIrq.setNextIrqEventTime(timaIrq.nextIrqEventTime() - dec);
|
|
|
|
@@ -68,8 +72,8 @@ void Tima::resetCc(unsigned long const oldCc, unsigned long const newCc, TimaInt
|
|
}
|
|
}
|
|
|
|
-void Tima::updateTima(unsigned long const cc) {
|
|
- unsigned long const ticks = (cc - lastUpdate_) >> timaClock[tac_ & 3];
|
|
+void Tima::updateTima(unsigned const cc) {
|
|
+ unsigned const ticks = (cc - lastUpdate_) >> timaClock[tac_ & 3];
|
|
lastUpdate_ += ticks << timaClock[tac_ & 3];
|
|
|
|
if (cc >= tmatime_) {
|
|
@@ -79,7 +83,7 @@ void Tima::updateTima(unsigned long const cc) {
|
|
tima_ = tma_;
|
|
}
|
|
|
|
- unsigned long tmp = tima_ + ticks;
|
|
+ unsigned tmp = tima_ + ticks;
|
|
while (tmp > 0x100)
|
|
tmp -= 0x100 - tma_;
|
|
|
|
@@ -98,7 +102,7 @@ void Tima::updateTima(unsigned long const cc) {
|
|
tima_ = tmp;
|
|
}
|
|
|
|
-void Tima::setTima(unsigned const data, unsigned long const cc, TimaInterruptRequester timaIrq) {
|
|
+void Tima::setTima(unsigned const data, unsigned const cc, TimaInterruptRequester timaIrq) {
|
|
if (tac_ & 0x04) {
|
|
updateIrq(cc, timaIrq);
|
|
updateTima(cc);
|
|
@@ -112,7 +116,7 @@ void Tima::setTima(unsigned const data, unsigned long const cc, TimaInterruptReq
|
|
tima_ = data;
|
|
}
|
|
|
|
-void Tima::setTma(unsigned const data, unsigned long const cc, TimaInterruptRequester timaIrq) {
|
|
+void Tima::setTma(unsigned const data, unsigned const cc, TimaInterruptRequester timaIrq) {
|
|
if (tac_ & 0x04) {
|
|
updateIrq(cc, timaIrq);
|
|
updateTima(cc);
|
|
@@ -121,9 +125,9 @@ void Tima::setTma(unsigned const data, unsigned long const cc, TimaInterruptRequ
|
|
tma_ = data;
|
|
}
|
|
|
|
-void Tima::setTac(unsigned const data, unsigned long const cc, TimaInterruptRequester timaIrq) {
|
|
+void Tima::setTac(unsigned const data, unsigned const cc, TimaInterruptRequester timaIrq) {
|
|
if (tac_ ^ data) {
|
|
- unsigned long nextIrqEventTime = timaIrq.nextIrqEventTime();
|
|
+ unsigned nextIrqEventTime = timaIrq.nextIrqEventTime();
|
|
|
|
if (tac_ & 0x04) {
|
|
updateIrq(cc, timaIrq);
|
|
@@ -153,7 +157,7 @@ void Tima::setTac(unsigned const data, unsigned long const cc, TimaInterruptRequ
|
|
tac_ = data;
|
|
}
|
|
|
|
-unsigned Tima::tima(unsigned long cc) {
|
|
+unsigned Tima::tima(unsigned cc) {
|
|
if (tac_ & 0x04)
|
|
updateTima(cc);
|
|
|
|
@@ -166,4 +170,13 @@ void Tima::doIrqEvent(TimaInterruptRequester timaIrq) {
|
|
+ ((256u - tma_) << timaClock[tac_ & 3]));
|
|
}
|
|
|
|
+void Tima::loadOrSave(loadsave& state)
|
|
+{
|
|
+ state(lastUpdate_);
|
|
+ state(tmatime_);
|
|
+ state(tima_);
|
|
+ state(tma_);
|
|
+ state(tac_);
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/tima.h b/libgambatte/src/tima.h
|
|
index 93afeb9..ce1f51e 100644
|
|
--- a/libgambatte/src/tima.h
|
|
+++ b/libgambatte/src/tima.h
|
|
@@ -19,6 +19,10 @@
|
|
#ifndef TIMA_H
|
|
#define TIMA_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include "interruptrequester.h"
|
|
|
|
namespace gambatte {
|
|
@@ -27,8 +31,8 @@ class TimaInterruptRequester {
|
|
public:
|
|
explicit TimaInterruptRequester(InterruptRequester &intreq) : intreq_(intreq) {}
|
|
void flagIrq() const { intreq_.flagIrq(4); }
|
|
- unsigned long nextIrqEventTime() const { return intreq_.eventTime(intevent_tima); }
|
|
- void setNextIrqEventTime(unsigned long time) const { intreq_.setEventTime<intevent_tima>(time); }
|
|
+ unsigned nextIrqEventTime() const { return intreq_.eventTime(intevent_tima); }
|
|
+ void setNextIrqEventTime(unsigned time) const { intreq_.setEventTime<intevent_tima>(time); }
|
|
|
|
private:
|
|
InterruptRequester &intreq_;
|
|
@@ -39,26 +43,26 @@ public:
|
|
Tima();
|
|
void saveState(SaveState &) const;
|
|
void loadState(const SaveState &, TimaInterruptRequester timaIrq);
|
|
- void resetCc(unsigned long oldCc, unsigned long newCc, TimaInterruptRequester timaIrq);
|
|
- void setTima(unsigned tima, unsigned long cc, TimaInterruptRequester timaIrq);
|
|
- void setTma(unsigned tma, unsigned long cc, TimaInterruptRequester timaIrq);
|
|
- void setTac(unsigned tac, unsigned long cc, TimaInterruptRequester timaIrq);
|
|
- unsigned tima(unsigned long cc);
|
|
+ void resetCc(unsigned oldCc, unsigned newCc, TimaInterruptRequester timaIrq);
|
|
+ void setTima(unsigned tima, unsigned cc, TimaInterruptRequester timaIrq);
|
|
+ void setTma(unsigned tma, unsigned cc, TimaInterruptRequester timaIrq);
|
|
+ void setTac(unsigned tac, unsigned cc, TimaInterruptRequester timaIrq);
|
|
+ unsigned tima(unsigned cc);
|
|
void doIrqEvent(TimaInterruptRequester timaIrq);
|
|
-
|
|
+ void updateTima(unsigned cc);
|
|
+ void loadOrSave(loadsave& state);
|
|
private:
|
|
- unsigned long lastUpdate_;
|
|
- unsigned long tmatime_;
|
|
+ unsigned lastUpdate_;
|
|
+ unsigned tmatime_;
|
|
unsigned char tima_;
|
|
unsigned char tma_;
|
|
unsigned char tac_;
|
|
|
|
- void updateIrq(unsigned long const cc, TimaInterruptRequester timaIrq) {
|
|
+ void updateIrq(unsigned const cc, TimaInterruptRequester timaIrq) {
|
|
while (cc >= timaIrq.nextIrqEventTime())
|
|
doIrqEvent(timaIrq);
|
|
}
|
|
|
|
- void updateTima(unsigned long cc);
|
|
};
|
|
|
|
}
|
|
diff --git a/libgambatte/src/video.cpp b/libgambatte/src/video.cpp
|
|
index 3205e90..5cb4b08 100644
|
|
--- a/libgambatte/src/video.cpp
|
|
+++ b/libgambatte/src/video.cpp
|
|
@@ -21,19 +21,23 @@
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
-void LCD::setDmgPalette(unsigned long palette[], unsigned long const dmgColors[], unsigned data) {
|
|
+void LCD::setDmgPalette(uint_least32_t palette[], uint_least32_t const dmgColors[], unsigned data) {
|
|
palette[0] = dmgColors[data & 3];
|
|
palette[1] = dmgColors[data >> 2 & 3];
|
|
palette[2] = dmgColors[data >> 4 & 3];
|
|
palette[3] = dmgColors[data >> 6 & 3];
|
|
}
|
|
|
|
-static unsigned long gbcToRgb32(unsigned const bgr15) {
|
|
- unsigned long const r = bgr15 & 0x1F;
|
|
- unsigned long const g = bgr15 >> 5 & 0x1F;
|
|
- unsigned long const b = bgr15 >> 10 & 0x1F;
|
|
+static uint_least32_t gbcToRgb32(unsigned const bgr15) {
|
|
+ uint_least32_t const r = bgr15 & 0x1F;
|
|
+ uint_least32_t const g = bgr15 >> 5 & 0x1F;
|
|
+ uint_least32_t const b = bgr15 >> 10 & 0x1F;
|
|
|
|
return ((r * 13 + g * 2 + b) >> 1) << 16
|
|
| (g * 3 + b) << 9
|
|
@@ -85,7 +89,6 @@ LCD::LCD(unsigned char const *oamram, unsigned char const *vram,
|
|
dmgColorsRgb32_[i] = (3 - (i & 3)) * 85 * 0x010101ul;
|
|
|
|
reset(oamram, vram, false);
|
|
- setVideoBuffer(0, 160);
|
|
}
|
|
|
|
void LCD::reset(unsigned char const *oamram, unsigned char const *vram, bool cgb) {
|
|
@@ -94,8 +97,8 @@ void LCD::reset(unsigned char const *oamram, unsigned char const *vram, bool cgb
|
|
refreshPalettes();
|
|
}
|
|
|
|
-static unsigned long mode2IrqSchedule(unsigned const statReg,
|
|
- LyCounter const &lyCounter, unsigned long const cc) {
|
|
+static unsigned mode2IrqSchedule(unsigned const statReg,
|
|
+ LyCounter const &lyCounter, unsigned const cc) {
|
|
if (!(statReg & lcdstat_m2irqen))
|
|
return disabled_time;
|
|
|
|
@@ -113,16 +116,16 @@ static unsigned long mode2IrqSchedule(unsigned const statReg,
|
|
return cc + next;
|
|
}
|
|
|
|
-static unsigned long m0IrqTimeFromXpos166Time(unsigned long xpos166Time, bool cgb, bool ds) {
|
|
+static unsigned m0IrqTimeFromXpos166Time(unsigned xpos166Time, bool cgb, bool ds) {
|
|
return xpos166Time + cgb - ds;
|
|
}
|
|
|
|
-static unsigned long hdmaTimeFromM0Time(unsigned long m0Time, bool ds) {
|
|
+static unsigned hdmaTimeFromM0Time(unsigned m0Time, bool ds) {
|
|
return m0Time + 1 - ds;
|
|
}
|
|
|
|
-static unsigned long nextHdmaTime(unsigned long lastM0Time,
|
|
- unsigned long nextM0Time, unsigned long cc, bool ds) {
|
|
+static unsigned nextHdmaTime(unsigned lastM0Time,
|
|
+ unsigned nextM0Time, unsigned cc, bool ds) {
|
|
return cc < hdmaTimeFromM0Time(lastM0Time, ds)
|
|
? hdmaTimeFromM0Time(lastM0Time, ds)
|
|
: hdmaTimeFromM0Time(nextM0Time, ds);
|
|
@@ -160,11 +163,11 @@ void LCD::loadState(SaveState const &state, unsigned char const *const oamram) {
|
|
eventTimes_.setm<memevent_oneshot_statirq>(
|
|
state.ppu.pendingLcdstatIrq
|
|
? ppu_.now() + 1
|
|
- : static_cast<unsigned long>(disabled_time));
|
|
+ : static_cast<unsigned>(disabled_time));
|
|
eventTimes_.setm<memevent_oneshot_updatewy2>(
|
|
state.ppu.oldWy != state.mem.ioamhram.get()[0x14A]
|
|
? ppu_.now() + 1
|
|
- : static_cast<unsigned long>(disabled_time));
|
|
+ : static_cast<unsigned>(disabled_time));
|
|
eventTimes_.set<event_ly>(ppu_.lyCounter().time());
|
|
eventTimes_.setm<memevent_spritemap>(
|
|
SpriteMapper::schedule(ppu_.lyCounter(), ppu_.now()));
|
|
@@ -175,11 +178,11 @@ void LCD::loadState(SaveState const &state, unsigned char const *const oamram) {
|
|
mode2IrqSchedule(statReg_, ppu_.lyCounter(), ppu_.now()));
|
|
eventTimes_.setm<memevent_m0irq>(statReg_ & lcdstat_m0irqen
|
|
? ppu_.now() + state.ppu.nextM0Irq
|
|
- : static_cast<unsigned long>(disabled_time));
|
|
+ : static_cast<unsigned>(disabled_time));
|
|
eventTimes_.setm<memevent_hdma>(state.mem.hdmaTransfer
|
|
? nextHdmaTime(ppu_.lastM0Time(), nextM0Time_.predictedNextM0Time(),
|
|
ppu_.now(), isDoubleSpeed())
|
|
- : static_cast<unsigned long>(disabled_time));
|
|
+ : static_cast<unsigned>(disabled_time));
|
|
} else for (int i = 0; i < num_memevents; ++i)
|
|
eventTimes_.set(MemEvent(i), disabled_time);
|
|
|
|
@@ -230,7 +233,7 @@ struct Blend {
|
|
};
|
|
|
|
template<typename T>
|
|
-static void clear(T *buf, unsigned long color, std::ptrdiff_t dpitch) {
|
|
+static void clear(T *buf, uint_least32_t color, std::ptrdiff_t dpitch) {
|
|
unsigned lines = 144;
|
|
|
|
while (lines--) {
|
|
@@ -241,11 +244,11 @@ static void clear(T *buf, unsigned long color, std::ptrdiff_t dpitch) {
|
|
|
|
}
|
|
|
|
-void LCD::updateScreen(bool const blanklcd, unsigned long const cycleCounter) {
|
|
+void LCD::updateScreen(bool const blanklcd, unsigned const cycleCounter, uint_least32_t* vbuffer, unsigned vpitch) {
|
|
update(cycleCounter);
|
|
|
|
if (blanklcd && ppu_.frameBuf().fb()) {
|
|
- unsigned long color = ppu_.cgb() ? gbcToRgb32(0xFFFF) : dmgColorsRgb32_[0];
|
|
+ uint_least32_t color = ppu_.cgb() ? gbcToRgb32(0xFFFF) : dmgColorsRgb32_[0];
|
|
clear(ppu_.frameBuf().fb(), color, ppu_.frameBuf().pitch());
|
|
}
|
|
|
|
@@ -268,14 +271,15 @@ void LCD::updateScreen(bool const blanklcd, unsigned long const cycleCounter) {
|
|
} else
|
|
osdElement_.reset();
|
|
}
|
|
+ ppu_.frameBuf().blit(vbuffer, vpitch);
|
|
}
|
|
|
|
-void LCD::resetCc(unsigned long const oldCc, unsigned long const newCc) {
|
|
+void LCD::resetCc(unsigned const oldCc, unsigned const newCc) {
|
|
update(oldCc);
|
|
ppu_.resetCc(oldCc, newCc);
|
|
|
|
if (ppu_.lcdc() & lcdc_en) {
|
|
- unsigned long const dec = oldCc - newCc;
|
|
+ unsigned const dec = oldCc - newCc;
|
|
|
|
nextM0Time_.invalidatePredictedNextM0Time();
|
|
lycIrq_.reschedule(ppu_.lyCounter(), newCc);
|
|
@@ -289,7 +293,7 @@ void LCD::resetCc(unsigned long const oldCc, unsigned long const newCc) {
|
|
}
|
|
}
|
|
|
|
-void LCD::speedChange(unsigned long const cc) {
|
|
+void LCD::speedChange(unsigned const cc) {
|
|
update(cc);
|
|
ppu_.speedChange(cc);
|
|
|
|
@@ -316,14 +320,14 @@ void LCD::speedChange(unsigned long const cc) {
|
|
}
|
|
}
|
|
|
|
-static unsigned long m0TimeOfCurrentLine(
|
|
- unsigned long nextLyTime,
|
|
- unsigned long lastM0Time,
|
|
- unsigned long nextM0Time) {
|
|
+static unsigned m0TimeOfCurrentLine(
|
|
+ unsigned nextLyTime,
|
|
+ unsigned lastM0Time,
|
|
+ unsigned nextM0Time) {
|
|
return nextM0Time < nextLyTime ? nextM0Time : lastM0Time;
|
|
}
|
|
|
|
-unsigned long LCD::m0TimeOfCurrentLine(unsigned long const cc) {
|
|
+unsigned LCD::m0TimeOfCurrentLine(unsigned const cc) {
|
|
if (cc >= nextM0Time_.predictedNextM0Time()) {
|
|
update(cc);
|
|
nextM0Time_.predictNextM0Time(ppu_);
|
|
@@ -334,20 +338,20 @@ unsigned long LCD::m0TimeOfCurrentLine(unsigned long const cc) {
|
|
}
|
|
|
|
static bool isHdmaPeriod(LyCounter const &lyCounter,
|
|
- unsigned long m0TimeOfCurrentLy, unsigned long cc) {
|
|
+ unsigned m0TimeOfCurrentLy, unsigned cc) {
|
|
int timeToNextLy = lyCounter.time() - cc;
|
|
return lyCounter.ly() < 144 && timeToNextLy > 4
|
|
&& cc >= hdmaTimeFromM0Time(m0TimeOfCurrentLy, lyCounter.isDoubleSpeed());
|
|
}
|
|
|
|
-void LCD::enableHdma(unsigned long const cycleCounter) {
|
|
+void LCD::enableHdma(unsigned const cycleCounter) {
|
|
if (cycleCounter >= nextM0Time_.predictedNextM0Time()) {
|
|
update(cycleCounter);
|
|
nextM0Time_.predictNextM0Time(ppu_);
|
|
} else if (cycleCounter >= eventTimes_.nextEventTime())
|
|
update(cycleCounter);
|
|
|
|
- unsigned long const m0TimeCurLy =
|
|
+ unsigned const m0TimeCurLy =
|
|
gambatte::m0TimeOfCurrentLine(ppu_.lyCounter().time(),
|
|
ppu_.lastM0Time(),
|
|
nextM0Time_.predictedNextM0Time());
|
|
@@ -359,14 +363,14 @@ void LCD::enableHdma(unsigned long const cycleCounter) {
|
|
cycleCounter, isDoubleSpeed()));
|
|
}
|
|
|
|
-void LCD::disableHdma(unsigned long const cycleCounter) {
|
|
+void LCD::disableHdma(unsigned const cycleCounter) {
|
|
if (cycleCounter >= eventTimes_.nextEventTime())
|
|
update(cycleCounter);
|
|
|
|
eventTimes_.setm<memevent_hdma>(disabled_time);
|
|
}
|
|
|
|
-bool LCD::vramAccessible(unsigned long const cc) {
|
|
+bool LCD::vramAccessible(unsigned const cc) {
|
|
if (cc >= eventTimes_.nextEventTime())
|
|
update(cc);
|
|
|
|
@@ -376,7 +380,7 @@ bool LCD::vramAccessible(unsigned long const cc) {
|
|
|| cc + isDoubleSpeed() - ppu_.cgb() + 2 >= m0TimeOfCurrentLine(cc);
|
|
}
|
|
|
|
-bool LCD::cgbpAccessible(unsigned long const cc) {
|
|
+bool LCD::cgbpAccessible(unsigned const cc) {
|
|
if (cc >= eventTimes_.nextEventTime())
|
|
update(cc);
|
|
|
|
@@ -387,27 +391,27 @@ bool LCD::cgbpAccessible(unsigned long const cc) {
|
|
}
|
|
|
|
static void doCgbColorChange(unsigned char *pdata,
|
|
- unsigned long *palette, unsigned index, unsigned data) {
|
|
+ uint_least32_t *palette, unsigned index, unsigned data) {
|
|
pdata[index] = data;
|
|
index >>= 1;
|
|
palette[index] = gbcToRgb32(pdata[index * 2] | pdata[index * 2 + 1] << 8);
|
|
}
|
|
|
|
-void LCD::doCgbBgColorChange(unsigned index, unsigned data, unsigned long cc) {
|
|
+void LCD::doCgbBgColorChange(unsigned index, unsigned data, unsigned cc) {
|
|
if (cgbpAccessible(cc)) {
|
|
update(cc);
|
|
doCgbColorChange(bgpData_, ppu_.bgPalette(), index, data);
|
|
}
|
|
}
|
|
|
|
-void LCD::doCgbSpColorChange(unsigned index, unsigned data, unsigned long cc) {
|
|
+void LCD::doCgbSpColorChange(unsigned index, unsigned data, unsigned cc) {
|
|
if (cgbpAccessible(cc)) {
|
|
update(cc);
|
|
doCgbColorChange(objpData_, ppu_.spPalette(), index, data);
|
|
}
|
|
}
|
|
|
|
-bool LCD::oamReadable(unsigned long const cc) {
|
|
+bool LCD::oamReadable(unsigned const cc) {
|
|
if (!(ppu_.lcdc() & lcdc_en) || ppu_.inactivePeriodAfterDisplayEnable(cc))
|
|
return true;
|
|
|
|
@@ -421,7 +425,7 @@ bool LCD::oamReadable(unsigned long const cc) {
|
|
|| cc + isDoubleSpeed() - ppu_.cgb() + 2 >= m0TimeOfCurrentLine(cc);
|
|
}
|
|
|
|
-bool LCD::oamWritable(unsigned long const cc) {
|
|
+bool LCD::oamWritable(unsigned const cc) {
|
|
if (!(ppu_.lcdc() & lcdc_en) || ppu_.inactivePeriodAfterDisplayEnable(cc))
|
|
return true;
|
|
|
|
@@ -442,7 +446,7 @@ void LCD::mode3CyclesChange() {
|
|
if (eventTimes_(memevent_m0irq) != disabled_time
|
|
&& eventTimes_(memevent_m0irq)
|
|
> m0IrqTimeFromXpos166Time(ppu_.now(), ppu_.cgb(), ds)) {
|
|
- unsigned long t = m0IrqTimeFromXpos166Time(ppu_.predictedNextXposTime(166),
|
|
+ unsigned t = m0IrqTimeFromXpos166Time(ppu_.predictedNextXposTime(166),
|
|
ppu_.cgb(), ds);
|
|
eventTimes_.setm<memevent_m0irq>(t);
|
|
}
|
|
@@ -455,13 +459,13 @@ void LCD::mode3CyclesChange() {
|
|
}
|
|
}
|
|
|
|
-void LCD::wxChange(unsigned newValue, unsigned long cycleCounter) {
|
|
+void LCD::wxChange(unsigned newValue, unsigned cycleCounter) {
|
|
update(cycleCounter + isDoubleSpeed() + 1);
|
|
ppu_.setWx(newValue);
|
|
mode3CyclesChange();
|
|
}
|
|
|
|
-void LCD::wyChange(unsigned const newValue, unsigned long const cc) {
|
|
+void LCD::wyChange(unsigned const newValue, unsigned const cc) {
|
|
update(cc + 1);
|
|
ppu_.setWy(newValue);
|
|
|
|
@@ -479,18 +483,18 @@ void LCD::wyChange(unsigned const newValue, unsigned long const cc) {
|
|
}
|
|
}
|
|
|
|
-void LCD::scxChange(unsigned newScx, unsigned long cycleCounter) {
|
|
+void LCD::scxChange(unsigned newScx, unsigned cycleCounter) {
|
|
update(cycleCounter + ppu_.cgb() + isDoubleSpeed());
|
|
ppu_.setScx(newScx);
|
|
mode3CyclesChange();
|
|
}
|
|
|
|
-void LCD::scyChange(unsigned newValue, unsigned long cycleCounter) {
|
|
+void LCD::scyChange(unsigned newValue, unsigned cycleCounter) {
|
|
update(cycleCounter + ppu_.cgb() + isDoubleSpeed());
|
|
ppu_.setScy(newValue);
|
|
}
|
|
|
|
-void LCD::oamChange(unsigned long cc) {
|
|
+void LCD::oamChange(unsigned cc) {
|
|
if (ppu_.lcdc() & lcdc_en) {
|
|
update(cc);
|
|
ppu_.oamChange(cc);
|
|
@@ -498,7 +502,7 @@ void LCD::oamChange(unsigned long cc) {
|
|
}
|
|
}
|
|
|
|
-void LCD::oamChange(unsigned char const *oamram, unsigned long cc) {
|
|
+void LCD::oamChange(unsigned char const *oamram, unsigned cc) {
|
|
update(cc);
|
|
ppu_.oamChange(oamram, cc);
|
|
|
|
@@ -506,7 +510,7 @@ void LCD::oamChange(unsigned char const *oamram, unsigned long cc) {
|
|
eventTimes_.setm<memevent_spritemap>(SpriteMapper::schedule(ppu_.lyCounter(), cc));
|
|
}
|
|
|
|
-void LCD::lcdcChange(unsigned const data, unsigned long const cc) {
|
|
+void LCD::lcdcChange(unsigned const data, unsigned const cc) {
|
|
unsigned const oldLcdc = ppu_.lcdc();
|
|
update(cc);
|
|
|
|
@@ -547,7 +551,7 @@ void LCD::lcdcChange(unsigned const data, unsigned long const cc) {
|
|
| (data & (lcdc_tdsel | lcdc_obj2x)), cc);
|
|
|
|
if ((oldLcdc ^ data) & lcdc_obj2x) {
|
|
- unsigned long t = SpriteMapper::schedule(ppu_.lyCounter(), cc);
|
|
+ unsigned t = SpriteMapper::schedule(ppu_.lyCounter(), cc);
|
|
eventTimes_.setm<memevent_spritemap>(t);
|
|
}
|
|
|
|
@@ -560,7 +564,7 @@ void LCD::lcdcChange(unsigned const data, unsigned long const cc) {
|
|
ppu_.setLcdc(data, cc);
|
|
|
|
if ((oldLcdc ^ data) & lcdc_obj2x) {
|
|
- unsigned long t = SpriteMapper::schedule(ppu_.lyCounter(), cc);
|
|
+ unsigned t = SpriteMapper::schedule(ppu_.lyCounter(), cc);
|
|
eventTimes_.setm<memevent_spritemap>(t);
|
|
}
|
|
|
|
@@ -578,7 +582,7 @@ struct LyCnt {
|
|
LyCnt(unsigned ly, int timeToNextLy) : ly(ly), timeToNextLy(timeToNextLy) {}
|
|
};
|
|
|
|
-static LyCnt const getLycCmpLy(LyCounter const &lyCounter, unsigned long cc) {
|
|
+static LyCnt const getLycCmpLy(LyCounter const &lyCounter, unsigned cc) {
|
|
unsigned ly = lyCounter.ly();
|
|
int timeToNextLy = lyCounter.time() - cc;
|
|
|
|
@@ -596,7 +600,7 @@ static LyCnt const getLycCmpLy(LyCounter const &lyCounter, unsigned long cc) {
|
|
|
|
} // anon ns
|
|
|
|
-inline bool LCD::statChangeTriggersStatIrqDmg(unsigned const old, unsigned long const cc) {
|
|
+inline bool LCD::statChangeTriggersStatIrqDmg(unsigned const old, unsigned const cc) {
|
|
LyCnt const lycCmp = getLycCmpLy(ppu_.lyCounter(), cc);
|
|
|
|
if (ppu_.lyCounter().ly() < 144) {
|
|
@@ -624,7 +628,7 @@ static bool statChangeTriggersM2IrqCgb(unsigned const old,
|
|
}
|
|
|
|
inline bool LCD::statChangeTriggersM0LycOrM1StatIrqCgb(
|
|
- unsigned const old, unsigned const data, unsigned long const cc) {
|
|
+ unsigned const old, unsigned const data, unsigned const cc) {
|
|
unsigned const ly = ppu_.lyCounter().ly();
|
|
int const timeToNextLy = ppu_.lyCounter().time() - cc;
|
|
LyCnt const lycCmp = getLycCmpLy(ppu_.lyCounter(), cc);
|
|
@@ -652,7 +656,7 @@ inline bool LCD::statChangeTriggersM0LycOrM1StatIrqCgb(
|
|
}
|
|
|
|
inline bool LCD::statChangeTriggersStatIrqCgb(
|
|
- unsigned const old, unsigned const data, unsigned long const cc) {
|
|
+ unsigned const old, unsigned const data, unsigned const cc) {
|
|
if (!(data & ~old & ( lcdstat_lycirqen
|
|
| lcdstat_m2irqen
|
|
| lcdstat_m1irqen
|
|
@@ -666,13 +670,13 @@ inline bool LCD::statChangeTriggersStatIrqCgb(
|
|
|| statChangeTriggersM2IrqCgb(old, data, ly, timeToNextLy);
|
|
}
|
|
|
|
-inline bool LCD::statChangeTriggersStatIrq(unsigned old, unsigned data, unsigned long cc) {
|
|
+inline bool LCD::statChangeTriggersStatIrq(unsigned old, unsigned data, unsigned cc) {
|
|
return ppu_.cgb()
|
|
? statChangeTriggersStatIrqCgb(old, data, cc)
|
|
: statChangeTriggersStatIrqDmg(old, cc);
|
|
}
|
|
|
|
-void LCD::lcdstatChange(unsigned const data, unsigned long const cc) {
|
|
+void LCD::lcdstatChange(unsigned const data, unsigned const cc) {
|
|
if (cc >= eventTimes_.nextEventTime())
|
|
update(cc);
|
|
|
|
@@ -706,7 +710,7 @@ void LCD::lcdstatChange(unsigned const data, unsigned long const cc) {
|
|
|
|
static unsigned incLy(unsigned ly) { return ly == 153 ? 0 : ly + 1; }
|
|
|
|
-inline bool LCD::lycRegChangeStatTriggerBlockedByM0OrM1Irq(unsigned long const cc) {
|
|
+inline bool LCD::lycRegChangeStatTriggerBlockedByM0OrM1Irq(unsigned const cc) {
|
|
int const timeToNextLy = ppu_.lyCounter().time() - cc;
|
|
if (ppu_.lyCounter().ly() < 144) {
|
|
return (statReg_ & lcdstat_m0irqen)
|
|
@@ -721,7 +725,7 @@ inline bool LCD::lycRegChangeStatTriggerBlockedByM0OrM1Irq(unsigned long const c
|
|
}
|
|
|
|
bool LCD::lycRegChangeTriggersStatIrq(
|
|
- unsigned const old, unsigned const data, unsigned long const cc) {
|
|
+ unsigned const old, unsigned const data, unsigned const cc) {
|
|
if (!(statReg_ & lcdstat_lycirqen) || data >= 154
|
|
|| lycRegChangeStatTriggerBlockedByM0OrM1Irq(cc)) {
|
|
return false;
|
|
@@ -739,7 +743,7 @@ bool LCD::lycRegChangeTriggersStatIrq(
|
|
return data == lycCmp.ly;
|
|
}
|
|
|
|
-void LCD::lycRegChange(unsigned const data, unsigned long const cc) {
|
|
+void LCD::lycRegChange(unsigned const data, unsigned const cc) {
|
|
unsigned const old = lycIrq_.lycReg();
|
|
if (data == old)
|
|
return;
|
|
@@ -762,7 +766,7 @@ void LCD::lycRegChange(unsigned const data, unsigned long const cc) {
|
|
}
|
|
}
|
|
|
|
-unsigned LCD::getStat(unsigned const lycReg, unsigned long const cc) {
|
|
+unsigned LCD::getStat(unsigned const lycReg, unsigned const cc) {
|
|
unsigned stat = 0;
|
|
|
|
if (ppu_.lcdc() & lcdc_en) {
|
|
@@ -815,7 +819,7 @@ inline void LCD::doMode2IrqEvent() {
|
|
m2IrqStatReg_ = statReg_;
|
|
|
|
if (!(statReg_ & lcdstat_m0irqen)) {
|
|
- unsigned long nextTime = eventTimes_(memevent_m2irq) + ppu_.lyCounter().lineTime();
|
|
+ unsigned nextTime = eventTimes_(memevent_m2irq) + ppu_.lyCounter().lineTime();
|
|
if (ly == 0) {
|
|
nextTime -= 4;
|
|
} else if (ly == 143)
|
|
@@ -878,7 +882,7 @@ inline void LCD::event() {
|
|
eventTimes_.setm<memevent_m0irq>(statReg_ & lcdstat_m0irqen
|
|
? m0IrqTimeFromXpos166Time(ppu_.predictedNextXposTime(166),
|
|
ppu_.cgb(), isDoubleSpeed())
|
|
- : static_cast<unsigned long>(disabled_time));
|
|
+ : static_cast<unsigned>(disabled_time));
|
|
break;
|
|
|
|
case memevent_oneshot_statirq:
|
|
@@ -902,7 +906,7 @@ inline void LCD::event() {
|
|
}
|
|
}
|
|
|
|
-void LCD::update(unsigned long const cycleCounter) {
|
|
+void LCD::update(unsigned const cycleCounter) {
|
|
if (!(ppu_.lcdc() & lcdc_en))
|
|
return;
|
|
|
|
@@ -914,11 +918,11 @@ void LCD::update(unsigned long const cycleCounter) {
|
|
ppu_.update(cycleCounter);
|
|
}
|
|
|
|
-void LCD::setVideoBuffer(uint_least32_t *videoBuf, std::ptrdiff_t pitch) {
|
|
- ppu_.setFrameBuf(videoBuf, pitch);
|
|
+void LCD::setDmgPaletteColor(unsigned index, uint_least32_t rgb32) {
|
|
+ dmgColorsRgb32_[index] = rgb32;
|
|
}
|
|
|
|
-void LCD::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32) {
|
|
+void LCD::setDmgPaletteColor(unsigned palNum, unsigned colorNum, uint_least32_t rgb32) {
|
|
if (palNum > 2 || colorNum > 3)
|
|
return;
|
|
|
|
@@ -926,4 +930,18 @@ void LCD::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long r
|
|
refreshPalettes();
|
|
}
|
|
|
|
+void LCD::loadOrSave(loadsave& state) {
|
|
+ ppu_.loadOrSave(state);
|
|
+ state(dmgColorsRgb32_, 12);
|
|
+ state(bgpData_, 64);
|
|
+ state(objpData_, 64);
|
|
+ eventTimes_.loadOrSave(state);
|
|
+ m0Irq_.loadOrSave(state);
|
|
+ lycIrq_.loadOrSave(state);
|
|
+ nextM0Time_.loadOrSave(state);
|
|
+ state(statReg_);
|
|
+ state(m2IrqStatReg_);
|
|
+ state(m1IrqStatReg_);
|
|
+}
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/video.h b/libgambatte/src/video.h
|
|
index dbef702..105e761 100644
|
|
--- a/libgambatte/src/video.h
|
|
+++ b/libgambatte/src/video.h
|
|
@@ -19,6 +19,13 @@
|
|
#ifndef VIDEO_H
|
|
#define VIDEO_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
+#include "video/ppu.h"
|
|
+#include "video/lyc_irq.h"
|
|
+#include "video/next_m0_time.h"
|
|
#include "interruptrequester.h"
|
|
#include "minkeeper.h"
|
|
#include "osd_element.h"
|
|
@@ -39,7 +46,7 @@ public:
|
|
|
|
void flagHdmaReq() const { gambatte::flagHdmaReq(intreq_); }
|
|
void flagIrq(unsigned bit) const { intreq_.flagIrq(bit); }
|
|
- void setNextEventTime(unsigned long time) const { intreq_.setEventTime<intevent_video>(time); }
|
|
+ void setNextEventTime(unsigned time) const { intreq_.setEventTime<intevent_video>(time); }
|
|
|
|
private:
|
|
InterruptRequester &intreq_;
|
|
@@ -52,63 +59,63 @@ public:
|
|
void reset(unsigned char const *oamram, unsigned char const *vram, bool cgb);
|
|
void setStatePtrs(SaveState &state);
|
|
void saveState(SaveState &state) const;
|
|
+ void loadOrSave(loadsave& state);
|
|
void loadState(SaveState const &state, unsigned char const *oamram);
|
|
- void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32);
|
|
- void setVideoBuffer(uint_least32_t *videoBuf, std::ptrdiff_t pitch);
|
|
+ void setDmgPaletteColor(unsigned palNum, unsigned colorNum, uint_least32_t rgb32);
|
|
void setOsdElement(transfer_ptr<OsdElement> osdElement) { osdElement_ = osdElement; }
|
|
|
|
- void dmgBgPaletteChange(unsigned data, unsigned long cycleCounter) {
|
|
+ void dmgBgPaletteChange(unsigned data, unsigned cycleCounter) {
|
|
update(cycleCounter);
|
|
bgpData_[0] = data;
|
|
setDmgPalette(ppu_.bgPalette(), dmgColorsRgb32_, data);
|
|
}
|
|
|
|
- void dmgSpPalette1Change(unsigned data, unsigned long cycleCounter) {
|
|
+ void dmgSpPalette1Change(unsigned data, unsigned cycleCounter) {
|
|
update(cycleCounter);
|
|
objpData_[0] = data;
|
|
setDmgPalette(ppu_.spPalette(), dmgColorsRgb32_ + 4, data);
|
|
}
|
|
|
|
- void dmgSpPalette2Change(unsigned data, unsigned long cycleCounter) {
|
|
+ void dmgSpPalette2Change(unsigned data, unsigned cycleCounter) {
|
|
update(cycleCounter);
|
|
objpData_[1] = data;
|
|
setDmgPalette(ppu_.spPalette() + 4, dmgColorsRgb32_ + 8, data);
|
|
}
|
|
|
|
- void cgbBgColorChange(unsigned index, unsigned data, unsigned long cycleCounter) {
|
|
+ void cgbBgColorChange(unsigned index, unsigned data, unsigned cycleCounter) {
|
|
if (bgpData_[index] != data)
|
|
doCgbBgColorChange(index, data, cycleCounter);
|
|
}
|
|
|
|
- void cgbSpColorChange(unsigned index, unsigned data, unsigned long cycleCounter) {
|
|
+ void cgbSpColorChange(unsigned index, unsigned data, unsigned cycleCounter) {
|
|
if (objpData_[index] != data)
|
|
doCgbSpColorChange(index, data, cycleCounter);
|
|
}
|
|
|
|
- unsigned cgbBgColorRead(unsigned index, unsigned long cycleCounter) {
|
|
+ unsigned cgbBgColorRead(unsigned index, unsigned cycleCounter) {
|
|
return ppu_.cgb() & cgbpAccessible(cycleCounter) ? bgpData_[index] : 0xFF;
|
|
}
|
|
|
|
- unsigned cgbSpColorRead(unsigned index, unsigned long cycleCounter) {
|
|
+ unsigned cgbSpColorRead(unsigned index, unsigned cycleCounter) {
|
|
return ppu_.cgb() & cgbpAccessible(cycleCounter) ? objpData_[index] : 0xFF;
|
|
}
|
|
|
|
- void updateScreen(bool blanklcd, unsigned long cc);
|
|
- void resetCc(unsigned long oldCC, unsigned long newCc);
|
|
- void speedChange(unsigned long cycleCounter);
|
|
- bool vramAccessible(unsigned long cycleCounter);
|
|
- bool oamReadable(unsigned long cycleCounter);
|
|
- bool oamWritable(unsigned long cycleCounter);
|
|
- void wxChange(unsigned newValue, unsigned long cycleCounter);
|
|
- void wyChange(unsigned newValue, unsigned long cycleCounter);
|
|
- void oamChange(unsigned long cycleCounter);
|
|
- void oamChange(const unsigned char *oamram, unsigned long cycleCounter);
|
|
- void scxChange(unsigned newScx, unsigned long cycleCounter);
|
|
- void scyChange(unsigned newValue, unsigned long cycleCounter);
|
|
- void vramChange(unsigned long cycleCounter) { update(cycleCounter); }
|
|
- unsigned getStat(unsigned lycReg, unsigned long cycleCounter);
|
|
-
|
|
- unsigned getLyReg(unsigned long const cc) {
|
|
+ void updateScreen(bool blanklcd, unsigned cc, uint_least32_t* vbuffer, unsigned vpitch);
|
|
+ void resetCc(unsigned oldCC, unsigned newCc);
|
|
+ void speedChange(unsigned cycleCounter);
|
|
+ bool vramAccessible(unsigned cycleCounter);
|
|
+ bool oamReadable(unsigned cycleCounter);
|
|
+ bool oamWritable(unsigned cycleCounter);
|
|
+ void wxChange(unsigned newValue, unsigned cycleCounter);
|
|
+ void wyChange(unsigned newValue, unsigned cycleCounter);
|
|
+ void oamChange(unsigned cycleCounter);
|
|
+ void oamChange(const unsigned char *oamram, unsigned cycleCounter);
|
|
+ void scxChange(unsigned newScx, unsigned cycleCounter);
|
|
+ void scyChange(unsigned newValue, unsigned cycleCounter);
|
|
+ void vramChange(unsigned cycleCounter) { update(cycleCounter); }
|
|
+ unsigned getStat(unsigned lycReg, unsigned cycleCounter);
|
|
+
|
|
+ unsigned getLyReg(unsigned const cc) {
|
|
unsigned lyReg = 0;
|
|
|
|
if (ppu_.lcdc() & lcdc_en) {
|
|
@@ -130,14 +137,14 @@ public:
|
|
return lyReg;
|
|
}
|
|
|
|
- unsigned long nextMode1IrqTime() const { return eventTimes_(memevent_m1irq); }
|
|
- void lcdcChange(unsigned data, unsigned long cycleCounter);
|
|
- void lcdstatChange(unsigned data, unsigned long cycleCounter);
|
|
- void lycRegChange(unsigned data, unsigned long cycleCounter);
|
|
- void enableHdma(unsigned long cycleCounter);
|
|
- void disableHdma(unsigned long cycleCounter);
|
|
+ unsigned nextMode1IrqTime() const { return eventTimes_(memevent_m1irq); }
|
|
+ void lcdcChange(unsigned data, unsigned cycleCounter);
|
|
+ void lcdstatChange(unsigned data, unsigned cycleCounter);
|
|
+ void lycRegChange(unsigned data, unsigned cycleCounter);
|
|
+ void enableHdma(unsigned cycleCounter);
|
|
+ void disableHdma(unsigned cycleCounter);
|
|
bool hdmaIsEnabled() const { return eventTimes_(memevent_hdma) != disabled_time; }
|
|
- void update(unsigned long cycleCounter);
|
|
+ void update(unsigned cycleCounter);
|
|
bool isCgb() const { return ppu_.cgb(); }
|
|
bool isDoubleSpeed() const { return ppu_.lyCounter().isDoubleSpeed(); }
|
|
|
|
@@ -165,36 +172,41 @@ private:
|
|
}
|
|
|
|
Event nextEvent() const { return static_cast<Event>(eventMin_.min()); }
|
|
- unsigned long nextEventTime() const { return eventMin_.minValue(); }
|
|
- unsigned long operator()(Event e) const { return eventMin_.value(e); }
|
|
- template<Event e> void set(unsigned long time) { eventMin_.setValue<e>(time); }
|
|
- void set(Event e, unsigned long time) { eventMin_.setValue(e, time); }
|
|
+ unsigned nextEventTime() const { return eventMin_.minValue(); }
|
|
+ unsigned operator()(Event e) const { return eventMin_.value(e); }
|
|
+ template<Event e> void set(unsigned time) { eventMin_.setValue<e>(time); }
|
|
+ void set(Event e, unsigned time) { eventMin_.setValue(e, time); }
|
|
|
|
MemEvent nextMemEvent() const { return static_cast<MemEvent>(memEventMin_.min()); }
|
|
- unsigned long nextMemEventTime() const { return memEventMin_.minValue(); }
|
|
- unsigned long operator()(MemEvent e) const { return memEventMin_.value(e); }
|
|
+ unsigned nextMemEventTime() const { return memEventMin_.minValue(); }
|
|
+ unsigned operator()(MemEvent e) const { return memEventMin_.value(e); }
|
|
|
|
template<MemEvent e>
|
|
- void setm(unsigned long time) { memEventMin_.setValue<e>(time); setMemEvent(); }
|
|
- void set(MemEvent e, unsigned long time) { memEventMin_.setValue(e, time); setMemEvent(); }
|
|
+ void setm(unsigned time) { memEventMin_.setValue<e>(time); setMemEvent(); }
|
|
+ void set(MemEvent e, unsigned time) { memEventMin_.setValue(e, time); setMemEvent(); }
|
|
|
|
void flagIrq(unsigned bit) { memEventRequester_.flagIrq(bit); }
|
|
void flagHdmaReq() { memEventRequester_.flagHdmaReq(); }
|
|
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ eventMin_.loadOrSave(state);
|
|
+ memEventMin_.loadOrSave(state);
|
|
+ }
|
|
private:
|
|
MinKeeper<num_events> eventMin_;
|
|
MinKeeper<num_memevents> memEventMin_;
|
|
VideoInterruptRequester memEventRequester_;
|
|
|
|
void setMemEvent() {
|
|
- unsigned long nmet = nextMemEventTime();
|
|
+ unsigned nmet = nextMemEventTime();
|
|
eventMin_.setValue<event_mem>(nmet);
|
|
memEventRequester_.setNextEventTime(nmet);
|
|
}
|
|
+
|
|
};
|
|
|
|
PPU ppu_;
|
|
- unsigned long dmgColorsRgb32_[3 * 4];
|
|
+ uint_least32_t dmgColorsRgb32_[3 * 4];
|
|
unsigned char bgpData_[8 * 8];
|
|
unsigned char objpData_[8 * 8];
|
|
EventTimes eventTimes_;
|
|
@@ -206,24 +218,25 @@ private:
|
|
unsigned char m2IrqStatReg_;
|
|
unsigned char m1IrqStatReg_;
|
|
|
|
- static void setDmgPalette(unsigned long palette[],
|
|
- unsigned long const dmgColors[],
|
|
+ static void setDmgPalette(uint_least32_t palette[],
|
|
+ uint_least32_t const dmgColors[],
|
|
unsigned data);
|
|
+ void setDmgPaletteColor(unsigned index, uint_least32_t rgb32);
|
|
void refreshPalettes();
|
|
void setDBuffer();
|
|
void doMode2IrqEvent();
|
|
void event();
|
|
- unsigned long m0TimeOfCurrentLine(unsigned long cc);
|
|
- bool cgbpAccessible(unsigned long cycleCounter);
|
|
- bool lycRegChangeStatTriggerBlockedByM0OrM1Irq(unsigned long cc);
|
|
- bool lycRegChangeTriggersStatIrq(unsigned old, unsigned data, unsigned long cc);
|
|
- bool statChangeTriggersM0LycOrM1StatIrqCgb(unsigned old, unsigned data, unsigned long cc);
|
|
- bool statChangeTriggersStatIrqCgb(unsigned old, unsigned data, unsigned long cc);
|
|
- bool statChangeTriggersStatIrqDmg(unsigned old, unsigned long cc);
|
|
- bool statChangeTriggersStatIrq(unsigned old, unsigned data, unsigned long cc);
|
|
+ unsigned m0TimeOfCurrentLine(unsigned cc);
|
|
+ bool cgbpAccessible(unsigned cycleCounter);
|
|
+ bool lycRegChangeStatTriggerBlockedByM0OrM1Irq(unsigned cc);
|
|
+ bool lycRegChangeTriggersStatIrq(unsigned old, unsigned data, unsigned cc);
|
|
+ bool statChangeTriggersM0LycOrM1StatIrqCgb(unsigned old, unsigned data, unsigned cc);
|
|
+ bool statChangeTriggersStatIrqCgb(unsigned old, unsigned data, unsigned cc);
|
|
+ bool statChangeTriggersStatIrqDmg(unsigned old, unsigned cc);
|
|
+ bool statChangeTriggersStatIrq(unsigned old, unsigned data, unsigned cc);
|
|
void mode3CyclesChange();
|
|
- void doCgbBgColorChange(unsigned index, unsigned data, unsigned long cycleCounter);
|
|
- void doCgbSpColorChange(unsigned index, unsigned data, unsigned long cycleCounter);
|
|
+ void doCgbBgColorChange(unsigned index, unsigned data, unsigned cycleCounter);
|
|
+ void doCgbSpColorChange(unsigned index, unsigned data, unsigned cycleCounter);
|
|
};
|
|
|
|
}
|
|
diff --git a/libgambatte/src/video/ly_counter.cpp b/libgambatte/src/video/ly_counter.cpp
|
|
index 0eb2961..d930d66 100644
|
|
--- a/libgambatte/src/video/ly_counter.cpp
|
|
+++ b/libgambatte/src/video/ly_counter.cpp
|
|
@@ -19,6 +19,10 @@
|
|
#include "ly_counter.h"
|
|
#include "../savestate.h"
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
LyCounter::LyCounter()
|
|
@@ -39,23 +43,23 @@ void LyCounter::doEvent() {
|
|
time_ = time_ + lineTime_;
|
|
}
|
|
|
|
-unsigned long LyCounter::nextLineCycle(unsigned const lineCycle, unsigned long const cc) const {
|
|
- unsigned long tmp = time_ + (lineCycle << ds_);
|
|
+unsigned LyCounter::nextLineCycle(unsigned const lineCycle, unsigned const cc) const {
|
|
+ unsigned tmp = time_ + (lineCycle << ds_);
|
|
if (tmp - cc > lineTime_)
|
|
tmp -= lineTime_;
|
|
|
|
return tmp;
|
|
}
|
|
|
|
-unsigned long LyCounter::nextFrameCycle(unsigned long const frameCycle, unsigned long const cc) const {
|
|
- unsigned long tmp = time_ + (((153U - ly()) * 456U + frameCycle) << ds_);
|
|
+unsigned LyCounter::nextFrameCycle(unsigned const frameCycle, unsigned const cc) const {
|
|
+ unsigned tmp = time_ + (((153U - ly()) * 456U + frameCycle) << ds_);
|
|
if (tmp - cc > 70224U << ds_)
|
|
tmp -= 70224U << ds_;
|
|
|
|
return tmp;
|
|
}
|
|
|
|
-void LyCounter::reset(unsigned long videoCycles, unsigned long lastUpdate) {
|
|
+void LyCounter::reset(unsigned videoCycles, unsigned lastUpdate) {
|
|
ly_ = videoCycles / 456;
|
|
time_ = lastUpdate + ((456 - (videoCycles - ly_ * 456ul)) << isDoubleSpeed());
|
|
}
|
|
diff --git a/libgambatte/src/video/ly_counter.h b/libgambatte/src/video/ly_counter.h
|
|
index 1defd1a..7c4d834 100644
|
|
--- a/libgambatte/src/video/ly_counter.h
|
|
+++ b/libgambatte/src/video/ly_counter.h
|
|
@@ -18,6 +18,11 @@
|
|
***************************************************************************/
|
|
#ifndef LY_COUNTER_H
|
|
#define LY_COUNTER_H
|
|
+#include "../loadsave.h"
|
|
+
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
|
|
namespace gambatte {
|
|
|
|
@@ -29,24 +34,31 @@ public:
|
|
void doEvent();
|
|
bool isDoubleSpeed() const { return ds_; }
|
|
|
|
- unsigned long frameCycles(unsigned long cc) const {
|
|
+ unsigned frameCycles(unsigned cc) const {
|
|
return ly_ * 456ul + lineCycles(cc);
|
|
}
|
|
|
|
- unsigned lineCycles(unsigned long cc) const {
|
|
+ unsigned lineCycles(unsigned cc) const {
|
|
return 456u - ((time_ - cc) >> isDoubleSpeed());
|
|
}
|
|
|
|
unsigned lineTime() const { return lineTime_; }
|
|
unsigned ly() const { return ly_; }
|
|
- unsigned long nextLineCycle(unsigned lineCycle, unsigned long cycleCounter) const;
|
|
- unsigned long nextFrameCycle(unsigned long frameCycle, unsigned long cycleCounter) const;
|
|
- void reset(unsigned long videoCycles, unsigned long lastUpdate);
|
|
+
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ state(time_);
|
|
+ state(lineTime_);
|
|
+ state(ly_);
|
|
+ state(ds_);
|
|
+ }
|
|
+ unsigned nextLineCycle(unsigned lineCycle, unsigned cycleCounter) const;
|
|
+ unsigned nextFrameCycle(unsigned frameCycle, unsigned cycleCounter) const;
|
|
+ void reset(unsigned videoCycles, unsigned lastUpdate);
|
|
void setDoubleSpeed(bool ds);
|
|
- unsigned long time() const { return time_; }
|
|
+ unsigned time() const { return time_; }
|
|
|
|
private:
|
|
- unsigned long time_;
|
|
+ unsigned time_;
|
|
unsigned short lineTime_;
|
|
unsigned char ly_;
|
|
bool ds_;
|
|
diff --git a/libgambatte/src/video/lyc_irq.cpp b/libgambatte/src/video/lyc_irq.cpp
|
|
index 3c468e2..127d589 100644
|
|
--- a/libgambatte/src/video/lyc_irq.cpp
|
|
+++ b/libgambatte/src/video/lyc_irq.cpp
|
|
@@ -23,6 +23,10 @@
|
|
#include "savestate.h"
|
|
#include <algorithm>
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
LycIrq::LycIrq()
|
|
@@ -35,16 +39,16 @@ LycIrq::LycIrq()
|
|
{
|
|
}
|
|
|
|
-static unsigned long schedule(unsigned statReg,
|
|
- unsigned lycReg, LyCounter const &lyCounter, unsigned long cc) {
|
|
+static unsigned schedule(unsigned statReg,
|
|
+ unsigned lycReg, LyCounter const &lyCounter, unsigned cc) {
|
|
return (statReg & lcdstat_lycirqen) && lycReg < 154
|
|
? lyCounter.nextFrameCycle(lycReg ? lycReg * 456 : 153 * 456 + 8, cc)
|
|
- : static_cast<unsigned long>(disabled_time);
|
|
+ : static_cast<unsigned>(disabled_time);
|
|
}
|
|
|
|
void LycIrq::regChange(unsigned const statReg,
|
|
- unsigned const lycReg, LyCounter const &lyCounter, unsigned long const cc) {
|
|
- unsigned long const timeSrc = schedule(statReg, lycReg, lyCounter, cc);
|
|
+ unsigned const lycReg, LyCounter const &lyCounter, unsigned const cc) {
|
|
+ unsigned const timeSrc = schedule(statReg, lycReg, lyCounter, cc);
|
|
statRegSrc_ = statReg;
|
|
lycRegSrc_ = lycReg;
|
|
time_ = std::min(time_, timeSrc);
|
|
@@ -95,7 +99,7 @@ void LycIrq::saveState(SaveState &state) const {
|
|
state.ppu.lyc = lycReg_;
|
|
}
|
|
|
|
-void LycIrq::reschedule(LyCounter const &lyCounter, unsigned long cc) {
|
|
+void LycIrq::reschedule(LyCounter const &lyCounter, unsigned cc) {
|
|
time_ = std::min(schedule(statReg_ , lycReg_ , lyCounter, cc),
|
|
schedule(statRegSrc_, lycRegSrc_, lyCounter, cc));
|
|
}
|
|
diff --git a/libgambatte/src/video/lyc_irq.h b/libgambatte/src/video/lyc_irq.h
|
|
index 6dd7911..a24a9ba 100644
|
|
--- a/libgambatte/src/video/lyc_irq.h
|
|
+++ b/libgambatte/src/video/lyc_irq.h
|
|
@@ -19,6 +19,12 @@
|
|
#ifndef VIDEO_LYC_IRQ_H
|
|
#define VIDEO_LYC_IRQ_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
+#include "../loadsave.h"
|
|
+
|
|
namespace gambatte {
|
|
|
|
struct SaveState;
|
|
@@ -31,21 +37,30 @@ public:
|
|
unsigned lycReg() const { return lycRegSrc_; }
|
|
void loadState(SaveState const &state);
|
|
void saveState(SaveState &state) const;
|
|
- unsigned long time() const { return time_; }
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ state(time_);
|
|
+ state(lycRegSrc_);
|
|
+ state(statRegSrc_);
|
|
+ state(lycReg_);
|
|
+ state(statReg_);
|
|
+ state(cgb_);
|
|
+ }
|
|
+
|
|
+ unsigned time() const { return time_; }
|
|
void setCgb(bool cgb) { cgb_ = cgb; }
|
|
void lcdReset();
|
|
- void reschedule(LyCounter const &lyCounter, unsigned long cc);
|
|
+ void reschedule(LyCounter const &lyCounter, unsigned cc);
|
|
|
|
- void statRegChange(unsigned statReg, LyCounter const &lyCounter, unsigned long cc) {
|
|
+ void statRegChange(unsigned statReg, LyCounter const &lyCounter, unsigned cc) {
|
|
regChange(statReg, lycRegSrc_, lyCounter, cc);
|
|
}
|
|
|
|
- void lycRegChange(unsigned lycReg, LyCounter const &lyCounter, unsigned long cc) {
|
|
+ void lycRegChange(unsigned lycReg, LyCounter const &lyCounter, unsigned cc) {
|
|
regChange(statRegSrc_, lycReg, lyCounter, cc);
|
|
}
|
|
|
|
private:
|
|
- unsigned long time_;
|
|
+ unsigned time_;
|
|
unsigned char lycRegSrc_;
|
|
unsigned char statRegSrc_;
|
|
unsigned char lycReg_;
|
|
@@ -53,7 +68,7 @@ private:
|
|
bool cgb_;
|
|
|
|
void regChange(unsigned statReg, unsigned lycReg,
|
|
- LyCounter const &lyCounter, unsigned long cc);
|
|
+ LyCounter const &lyCounter, unsigned cc);
|
|
};
|
|
|
|
}
|
|
diff --git a/libgambatte/src/video/m0_irq.h b/libgambatte/src/video/m0_irq.h
|
|
index f07f62f..fb0af1e 100644
|
|
--- a/libgambatte/src/video/m0_irq.h
|
|
+++ b/libgambatte/src/video/m0_irq.h
|
|
@@ -20,13 +20,13 @@ public:
|
|
}
|
|
|
|
void statRegChange(unsigned statReg,
|
|
- unsigned long nextM0IrqTime, unsigned long cc, bool cgb) {
|
|
+ unsigned nextM0IrqTime, unsigned cc, bool cgb) {
|
|
if (nextM0IrqTime - cc > cgb * 2U)
|
|
statReg_ = statReg;
|
|
}
|
|
|
|
void lycRegChange(unsigned lycReg,
|
|
- unsigned long nextM0IrqTime, unsigned long cc,
|
|
+ unsigned nextM0IrqTime, unsigned cc,
|
|
bool ds, bool cgb) {
|
|
if (nextM0IrqTime - cc > cgb * 5 + 1U - ds)
|
|
lycReg_ = lycReg;
|
|
@@ -53,6 +53,11 @@ public:
|
|
|
|
unsigned statReg() const { return statReg_; }
|
|
|
|
+ void loadOrSave(loadsave& state)
|
|
+ {
|
|
+ state(statReg_);
|
|
+ state(lycReg_);
|
|
+ }
|
|
private:
|
|
unsigned char statReg_;
|
|
unsigned char lycReg_;
|
|
diff --git a/libgambatte/src/video/next_m0_time.h b/libgambatte/src/video/next_m0_time.h
|
|
index 5cea59d..9c7c0e3 100644
|
|
--- a/libgambatte/src/video/next_m0_time.h
|
|
+++ b/libgambatte/src/video/next_m0_time.h
|
|
@@ -1,6 +1,12 @@
|
|
#ifndef NEXT_M0_TIME_H_
|
|
#define NEXT_M0_TIME_H_
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
+#include "../loadsave.h"
|
|
+
|
|
namespace gambatte {
|
|
|
|
class NextM0Time {
|
|
@@ -10,6 +16,9 @@ public:
|
|
void invalidatePredictedNextM0Time() { predictedNextM0Time_ = 0; }
|
|
unsigned predictedNextM0Time() const { return predictedNextM0Time_; }
|
|
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ state(predictedNextM0Time_);
|
|
+ }
|
|
private:
|
|
unsigned predictedNextM0Time_;
|
|
};
|
|
diff --git a/libgambatte/src/video/ppu.cpp b/libgambatte/src/video/ppu.cpp
|
|
index fd0dc07..485b0d4 100644
|
|
--- a/libgambatte/src/video/ppu.cpp
|
|
+++ b/libgambatte/src/video/ppu.cpp
|
|
@@ -449,7 +449,7 @@ static void doFullTilesUnrolledDmg(PPUPriv &p, int const xend, uint_least32_t *c
|
|
|
|
unsigned const attrib = p.spriteList[i].attrib;
|
|
unsigned spword = p.spwordList[i];
|
|
- unsigned long const *const spPalette = p.spPalette + (attrib >> 2 & 4);
|
|
+ const uint_least32_t *const spPalette = p.spPalette + (attrib >> 2 & 4);
|
|
uint_least32_t *d = dst + pos;
|
|
|
|
if (!(attrib & attr_bgpriority)) {
|
|
@@ -564,7 +564,7 @@ static void doFullTilesUnrolledCgb(PPUPriv &p, int const xend, uint_least32_t *c
|
|
xpos += n;
|
|
|
|
do {
|
|
- unsigned long const *const bgPalette = p.bgPalette + (nattrib & 7) * 4;
|
|
+ uint_least32_t const *const bgPalette = p.bgPalette + (nattrib & 7) * 4;
|
|
dst[0] = bgPalette[ ntileword & 0x0003 ];
|
|
dst[1] = bgPalette[(ntileword & 0x000C) >> 2];
|
|
dst[2] = bgPalette[(ntileword & 0x0030) >> 4];
|
|
@@ -603,7 +603,7 @@ static void doFullTilesUnrolledCgb(PPUPriv &p, int const xend, uint_least32_t *c
|
|
uint_least32_t *const dst = dbufline + (xpos - 8);
|
|
unsigned const tileword = p.ntileword;
|
|
unsigned const attrib = p.nattrib;
|
|
- unsigned long const *const bgPalette = p.bgPalette + (attrib & 7) * 4;
|
|
+ uint_least32_t const *const bgPalette = p.bgPalette + (attrib & 7) * 4;
|
|
|
|
dst[0] = bgPalette[ tileword & 0x0003 ];
|
|
dst[1] = bgPalette[(tileword & 0x000C) >> 2];
|
|
@@ -639,7 +639,7 @@ static void doFullTilesUnrolledCgb(PPUPriv &p, int const xend, uint_least32_t *c
|
|
unsigned char const id = p.spriteList[i].oampos;
|
|
unsigned const sattrib = p.spriteList[i].attrib;
|
|
unsigned spword = p.spwordList[i];
|
|
- unsigned long const *const spPalette = p.spPalette + (sattrib & 7) * 4;
|
|
+ uint_least32_t const *const spPalette = p.spPalette + (sattrib & 7) * 4;
|
|
|
|
if (!((attrib | sattrib) & bgprioritymask)) {
|
|
unsigned char *const idt = idtab + pos;
|
|
@@ -805,7 +805,7 @@ static void plotPixel(PPUPriv &p) {
|
|
}
|
|
|
|
unsigned const twdata = tileword & ((p.lcdc & 1) | p.cgb) * 3;
|
|
- unsigned long pixel = p.bgPalette[twdata + (p.attrib & 7) * 4];
|
|
+ uint_least32_t pixel = p.bgPalette[twdata + (p.attrib & 7) * 4];
|
|
int i = static_cast<int>(p.nextSprite) - 1;
|
|
|
|
if (i >= 0 && int(p.spriteList[i].spx) > xpos - 8) {
|
|
@@ -866,8 +866,8 @@ static void plotPixelIfNoSprite(PPUPriv &p) {
|
|
plotPixel(p);
|
|
}
|
|
|
|
-static unsigned long nextM2Time(PPUPriv const &p) {
|
|
- unsigned long nextm2 = p.lyCounter.isDoubleSpeed()
|
|
+static unsigned nextM2Time(PPUPriv const &p) {
|
|
+ unsigned nextm2 = p.lyCounter.isDoubleSpeed()
|
|
? p.lyCounter.time() + (weMasterCheckPriorToLyIncLineCycle(true ) + m2_ds_offset) * 2 - 456 * 2
|
|
: p.lyCounter.time() + weMasterCheckPriorToLyIncLineCycle(p.cgb) - 456 ;
|
|
if (p.lyCounter.ly() == 143)
|
|
@@ -879,11 +879,11 @@ static unsigned long nextM2Time(PPUPriv const &p) {
|
|
static void xpos168(PPUPriv &p) {
|
|
p.lastM0Time = p.now - (p.cycles << p.lyCounter.isDoubleSpeed());
|
|
|
|
- unsigned long const nextm2 = nextM2Time(p);
|
|
+ unsigned const nextm2 = nextM2Time(p);
|
|
|
|
p.cycles = p.now >= nextm2
|
|
- ? long((p.now - nextm2) >> p.lyCounter.isDoubleSpeed())
|
|
- : -long((nextm2 - p.now) >> p.lyCounter.isDoubleSpeed());
|
|
+ ? signed((p.now - nextm2) >> p.lyCounter.isDoubleSpeed())
|
|
+ : -signed((nextm2 - p.now) >> p.lyCounter.isDoubleSpeed());
|
|
|
|
nextCall(0, p.lyCounter.ly() == 143 ? M2_Ly0::f0_ : M2_LyNon0::f0_, p);
|
|
}
|
|
@@ -1576,8 +1576,8 @@ std::size_t upperBound(T const a[], K e) {
|
|
|
|
struct CycleState {
|
|
PPUState const *state;
|
|
- long cycle;
|
|
- operator long() const { return cycle; }
|
|
+ signed cycle;
|
|
+ operator signed() const { return cycle; }
|
|
};
|
|
|
|
static PPUState const * decodeM3LoopState(unsigned state) {
|
|
@@ -1607,8 +1607,8 @@ static PPUState const * decodeM3LoopState(unsigned state) {
|
|
return 0;
|
|
}
|
|
|
|
-static long cyclesUntilM0Upperbound(PPUPriv const &p) {
|
|
- long cycles = 168 - p.xpos + 6;
|
|
+static signed cyclesUntilM0Upperbound(PPUPriv const &p) {
|
|
+ signed cycles = 168 - p.xpos + 6;
|
|
for (unsigned i = p.nextSprite; i < 10 && p.spriteList[i].spx < 168; ++i)
|
|
cycles += 11;
|
|
|
|
@@ -1647,17 +1647,17 @@ static void loadSpriteList(PPUPriv &p, SaveState const &ss) {
|
|
|
|
void PPU::loadState(SaveState const &ss, unsigned char const *const oamram) {
|
|
PPUState const *const m3loopState = decodeM3LoopState(ss.ppu.state);
|
|
- long const videoCycles = std::min(ss.ppu.videoCycles, 70223UL);
|
|
+ signed const videoCycles = std::min(ss.ppu.videoCycles, 70223U);
|
|
bool const ds = p_.cgb & ss.mem.ioamhram.get()[0x14D] >> 7;
|
|
- long const vcycs = videoCycles - ds * m2_ds_offset < 0
|
|
+ signed const vcycs = videoCycles - ds * m2_ds_offset < 0
|
|
? videoCycles - ds * m2_ds_offset + 70224
|
|
: videoCycles - ds * m2_ds_offset;
|
|
- long const lineCycles = static_cast<unsigned long>(vcycs) % 456;
|
|
+ signed const lineCycles = static_cast<unsigned>(vcycs) % 456;
|
|
|
|
p_.now = ss.cpu.cycleCounter;
|
|
p_.lcdc = ss.mem.ioamhram.get()[0x140];
|
|
p_.lyCounter.setDoubleSpeed(ds);
|
|
- p_.lyCounter.reset(std::min(ss.ppu.videoCycles, 70223ul), ss.cpu.cycleCounter);
|
|
+ p_.lyCounter.reset(std::min(ss.ppu.videoCycles, 70223u), ss.cpu.cycleCounter);
|
|
p_.spriteMapper.loadState(ss, oamram);
|
|
p_.winYPos = ss.ppu.winYPos;
|
|
p_.scy = ss.mem.ioamhram.get()[0x142];
|
|
@@ -1684,7 +1684,7 @@ void PPU::loadState(SaveState const &ss, unsigned char const *const oamram) {
|
|
&& lineCycles + cyclesUntilM0Upperbound(p_) < weMasterCheckPriorToLyIncLineCycle(p_.cgb)) {
|
|
p_.nextCallPtr = m3loopState;
|
|
p_.cycles = -1;
|
|
- } else if (vcycs < 143 * 456L + static_cast<long>(m3StartLineCycle(p_.cgb)) + max_m3start_cycles) {
|
|
+ } else if (vcycs < 143 * 456L + static_cast<signed>(m3StartLineCycle(p_.cgb)) + max_m3start_cycles) {
|
|
CycleState const lineCycleStates[] = {
|
|
{ &M3Start::f0_, m3StartLineCycle(p_.cgb) },
|
|
{ &M3Start::f1_, m3StartLineCycle(p_.cgb) + max_m3start_cycles },
|
|
@@ -1715,9 +1715,9 @@ void PPU::reset(unsigned char const *oamram, unsigned char const *vram, bool cgb
|
|
p_.spriteMapper.reset(oamram, cgb);
|
|
}
|
|
|
|
-void PPU::resetCc(unsigned long const oldCc, unsigned long const newCc) {
|
|
- unsigned long const dec = oldCc - newCc;
|
|
- unsigned long const videoCycles = lcdcEn(p_) ? p_.lyCounter.frameCycles(p_.now) : 0;
|
|
+void PPU::resetCc(unsigned const oldCc, unsigned const newCc) {
|
|
+ unsigned const dec = oldCc - newCc;
|
|
+ unsigned const videoCycles = lcdcEn(p_) ? p_.lyCounter.frameCycles(p_.now) : 0;
|
|
|
|
p_.now -= dec;
|
|
p_.lastM0Time = p_.lastM0Time ? p_.lastM0Time - dec : p_.lastM0Time;
|
|
@@ -1725,8 +1725,8 @@ void PPU::resetCc(unsigned long const oldCc, unsigned long const newCc) {
|
|
p_.spriteMapper.resetCycleCounter(oldCc, newCc);
|
|
}
|
|
|
|
-void PPU::speedChange(unsigned long const cycleCounter) {
|
|
- unsigned long const videoCycles = lcdcEn(p_) ? p_.lyCounter.frameCycles(p_.now) : 0;
|
|
+void PPU::speedChange(unsigned const cycleCounter) {
|
|
+ unsigned const videoCycles = lcdcEn(p_) ? p_.lyCounter.frameCycles(p_.now) : 0;
|
|
|
|
p_.spriteMapper.preSpeedChange(cycleCounter);
|
|
p_.lyCounter.setDoubleSpeed(!p_.lyCounter.isDoubleSpeed());
|
|
@@ -1741,12 +1741,12 @@ void PPU::speedChange(unsigned long const cycleCounter) {
|
|
}
|
|
}
|
|
|
|
-unsigned long PPU::predictedNextXposTime(unsigned xpos) const {
|
|
+unsigned PPU::predictedNextXposTime(unsigned xpos) const {
|
|
return p_.now
|
|
+ (p_.nextCallPtr->predictCyclesUntilXpos_f(p_, xpos, -p_.cycles) << p_.lyCounter.isDoubleSpeed());
|
|
}
|
|
|
|
-void PPU::setLcdc(unsigned const lcdc, unsigned long const cc) {
|
|
+void PPU::setLcdc(unsigned const lcdc, unsigned const cc) {
|
|
if ((p_.lcdc ^ lcdc) & lcdc & lcdc_en) {
|
|
p_.now = cc;
|
|
p_.lastM0Time = 0;
|
|
@@ -1776,7 +1776,7 @@ void PPU::setLcdc(unsigned const lcdc, unsigned long const cc) {
|
|
p_.lcdc = lcdc;
|
|
}
|
|
|
|
-void PPU::update(unsigned long const cc) {
|
|
+void PPU::update(unsigned const cc) {
|
|
int const cycles = (cc - p_.now) >> p_.lyCounter.isDoubleSpeed();
|
|
|
|
p_.now += cycles << p_.lyCounter.isDoubleSpeed();
|
|
@@ -1788,4 +1788,70 @@ void PPU::update(unsigned long const cc) {
|
|
}
|
|
}
|
|
|
|
+void PPUPriv::loadOrSave(loadsave& state)
|
|
+{
|
|
+ state(bgPalette, 32);
|
|
+ state(spPalette, 32);
|
|
+
|
|
+ state.startEnumeration();
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, NULL, 0);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M2_Ly0::f0_, 1);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M2_LyNon0::f0_, 2);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M2_LyNon0::f1_, 3);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Start::f0_, 4);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Start::f1_, 5);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::Tile::f0_, 6);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::Tile::f1_, 7);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::Tile::f2_, 8);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::Tile::f3_, 9);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::Tile::f4_, 10);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::Tile::f5_, 11);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::LoadSprites::f0_, 12);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::LoadSprites::f1_, 13);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::LoadSprites::f2_, 14);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::LoadSprites::f3_, 15);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::LoadSprites::f4_, 16);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::LoadSprites::f5_, 17);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::StartWindowDraw::f0_, 18);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::StartWindowDraw::f1_, 19);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::StartWindowDraw::f2_, 20);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::StartWindowDraw::f3_, 21);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::StartWindowDraw::f4_, 22);
|
|
+ state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::StartWindowDraw::f5_, 23);
|
|
+ state.endEnumeration();
|
|
+
|
|
+ state(now);
|
|
+ state(lastM0Time);
|
|
+ state(cycles);
|
|
+ state(tileword);
|
|
+ state(ntileword);
|
|
+ lyCounter.loadOrSave(state);
|
|
+ spriteMapper.loadOrSave(state);
|
|
+ framebuf.loadOrSave(state);
|
|
+
|
|
+ for(size_t i = 0; i < 11; i++)
|
|
+ spriteList[i].loadOrSave(state);
|
|
+ state(spwordList, 11);
|
|
+ state(lcdc);
|
|
+ state(scy);
|
|
+ state(scx);
|
|
+ state(wy);
|
|
+ state(wy2);
|
|
+ state(wx);
|
|
+ state(winDrawState);
|
|
+ state(wscx);
|
|
+ state(winYPos);
|
|
+ state(reg0);
|
|
+ state(reg1);
|
|
+ state(attrib);
|
|
+ state(nattrib);
|
|
+ state(nextSprite);
|
|
+ state(currentSprite);
|
|
+ state(xpos);
|
|
+ state(endx);
|
|
+ state(cgb);
|
|
+ state(weMaster);
|
|
+}
|
|
+
|
|
+
|
|
}
|
|
diff --git a/libgambatte/src/video/ppu.h b/libgambatte/src/video/ppu.h
|
|
index 1bd9a22..ea711b7 100644
|
|
--- a/libgambatte/src/video/ppu.h
|
|
+++ b/libgambatte/src/video/ppu.h
|
|
@@ -19,27 +19,50 @@
|
|
#ifndef PPU_H
|
|
#define PPU_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
+#include <cstring>
|
|
+#include "video/ly_counter.h"
|
|
+#include "video/sprite_mapper.h"
|
|
#include "lcddef.h"
|
|
#include "ly_counter.h"
|
|
#include "sprite_mapper.h"
|
|
#include "gbint.h"
|
|
+#include "../loadsave.h"
|
|
#include <cstddef>
|
|
|
|
namespace gambatte {
|
|
|
|
class PPUFrameBuf {
|
|
public:
|
|
- PPUFrameBuf() : buf_(0), fbline_(nullfbline()), pitch_(0) {}
|
|
+ PPUFrameBuf() : fbline_(nullfbline()), pitch_(160) { memset(buf_, 0, sizeof(buf_)); }
|
|
uint_least32_t * fb() const { return buf_; }
|
|
uint_least32_t * fbline() const { return fbline_; }
|
|
std::ptrdiff_t pitch() const { return pitch_; }
|
|
- void setBuf(uint_least32_t *buf, std::ptrdiff_t pitch) { buf_ = buf; pitch_ = pitch; fbline_ = nullfbline(); }
|
|
void setFbline(unsigned ly) { fbline_ = buf_ ? buf_ + std::ptrdiff_t(ly) * pitch_ : nullfbline(); }
|
|
+ void blit(uint_least32_t *const buf, const int pitch) const {
|
|
+ for(unsigned i = 0; i < 144; i++)
|
|
+ memcpy(buf + i * static_cast<signed>(pitch), buf_ + i * 160, 160 * sizeof(buf[0]));
|
|
+ }
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ state(buf_, 160*144);
|
|
+ state(pitch_);
|
|
+ bool var = (fbline_ != nullfbline());
|
|
+ state(var);
|
|
+ if(var) {
|
|
+ unsigned x = fbline_ - buf_;
|
|
+ state(x);
|
|
+ fbline_ = buf_ + x;
|
|
+ } else
|
|
+ fbline_ = nullfbline();
|
|
+ }
|
|
|
|
private:
|
|
- uint_least32_t *buf_;
|
|
+ mutable uint_least32_t buf_[160*144];
|
|
uint_least32_t *fbline_;
|
|
- std::ptrdiff_t pitch_;
|
|
+ int pitch_;
|
|
|
|
static uint_least32_t * nullfbline() { static uint_least32_t nullfbline_[160]; return nullfbline_; }
|
|
};
|
|
@@ -53,27 +76,34 @@ struct PPUState {
|
|
};
|
|
|
|
struct PPUPriv {
|
|
- unsigned long bgPalette[8 * 4];
|
|
- unsigned long spPalette[8 * 4];
|
|
- struct Sprite { unsigned char spx, oampos, line, attrib; } spriteList[11];
|
|
- unsigned short spwordList[11];
|
|
- unsigned char nextSprite;
|
|
- unsigned char currentSprite;
|
|
+ uint_least32_t bgPalette[8 * 4];
|
|
+ uint_least32_t spPalette[8 * 4];
|
|
|
|
unsigned char const *vram;
|
|
PPUState const *nextCallPtr;
|
|
|
|
- unsigned long now;
|
|
- unsigned long lastM0Time;
|
|
- long cycles;
|
|
+ unsigned now;
|
|
+ unsigned lastM0Time;
|
|
+ signed cycles;
|
|
|
|
unsigned tileword;
|
|
unsigned ntileword;
|
|
|
|
- SpriteMapper spriteMapper;
|
|
LyCounter lyCounter;
|
|
+ SpriteMapper spriteMapper;
|
|
PPUFrameBuf framebuf;
|
|
|
|
+ struct Sprite {
|
|
+ unsigned char spx, oampos, line, attrib;
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ state(spx);
|
|
+ state(oampos);
|
|
+ state(line);
|
|
+ state(attrib);
|
|
+ }
|
|
+ } spriteList[11];
|
|
+ unsigned short spwordList[11];
|
|
+
|
|
unsigned char lcdc;
|
|
unsigned char scy;
|
|
unsigned char scx;
|
|
@@ -87,12 +117,15 @@ struct PPUPriv {
|
|
unsigned char reg1;
|
|
unsigned char attrib;
|
|
unsigned char nattrib;
|
|
+ unsigned char nextSprite;
|
|
+ unsigned char currentSprite;
|
|
unsigned char xpos;
|
|
unsigned char endx;
|
|
|
|
bool cgb;
|
|
bool weMaster;
|
|
|
|
+ void loadOrSave(loadsave& state);
|
|
PPUPriv(NextM0Time &nextM0Time, unsigned char const *oamram, unsigned char const *vram);
|
|
};
|
|
|
|
@@ -103,39 +136,42 @@ public:
|
|
{
|
|
}
|
|
|
|
- unsigned long * bgPalette() { return p_.bgPalette; }
|
|
+ uint_least32_t * bgPalette() { return p_.bgPalette; }
|
|
bool cgb() const { return p_.cgb; }
|
|
void doLyCountEvent() { p_.lyCounter.doEvent(); }
|
|
- unsigned long doSpriteMapEvent(unsigned long time) { return p_.spriteMapper.doEvent(time); }
|
|
+ unsigned doSpriteMapEvent(unsigned time) { return p_.spriteMapper.doEvent(time); }
|
|
PPUFrameBuf const & frameBuf() const { return p_.framebuf; }
|
|
|
|
- bool inactivePeriodAfterDisplayEnable(unsigned long cc) const {
|
|
+ bool inactivePeriodAfterDisplayEnable(unsigned cc) const {
|
|
return p_.spriteMapper.inactivePeriodAfterDisplayEnable(cc);
|
|
}
|
|
|
|
- unsigned long lastM0Time() const { return p_.lastM0Time; }
|
|
+ unsigned lastM0Time() const { return p_.lastM0Time; }
|
|
unsigned lcdc() const { return p_.lcdc; }
|
|
void loadState(SaveState const &state, unsigned char const *oamram);
|
|
LyCounter const & lyCounter() const { return p_.lyCounter; }
|
|
- unsigned long now() const { return p_.now; }
|
|
- void oamChange(unsigned long cc) { p_.spriteMapper.oamChange(cc); }
|
|
- void oamChange(unsigned char const *oamram, unsigned long cc) { p_.spriteMapper.oamChange(oamram, cc); }
|
|
- unsigned long predictedNextXposTime(unsigned xpos) const;
|
|
+ unsigned now() const { return p_.now; }
|
|
+ void oamChange(unsigned cc) { p_.spriteMapper.oamChange(cc); }
|
|
+ void oamChange(unsigned char const *oamram, unsigned cc) { p_.spriteMapper.oamChange(oamram, cc); }
|
|
+ unsigned predictedNextXposTime(unsigned xpos) const;
|
|
void reset(unsigned char const *oamram, unsigned char const *vram, bool cgb);
|
|
- void resetCc(unsigned long oldCc, unsigned long newCc);
|
|
+ void resetCc(unsigned oldCc, unsigned newCc);
|
|
void saveState(SaveState &ss) const;
|
|
- void setFrameBuf(uint_least32_t *buf, std::ptrdiff_t pitch) { p_.framebuf.setBuf(buf, pitch); }
|
|
- void setLcdc(unsigned lcdc, unsigned long cc);
|
|
+ void flipDisplay(uint_least32_t *buf, unsigned pitch) { p_.framebuf.blit(buf, pitch); }
|
|
+ void setLcdc(unsigned lcdc, unsigned cc);
|
|
void setScx(unsigned scx) { p_.scx = scx; }
|
|
void setScy(unsigned scy) { p_.scy = scy; }
|
|
void setStatePtrs(SaveState &ss) { p_.spriteMapper.setStatePtrs(ss); }
|
|
void setWx(unsigned wx) { p_.wx = wx; }
|
|
void setWy(unsigned wy) { p_.wy = wy; }
|
|
void updateWy2() { p_.wy2 = p_.wy; }
|
|
- void speedChange(unsigned long cycleCounter);
|
|
- unsigned long * spPalette() { return p_.spPalette; }
|
|
- void update(unsigned long cc);
|
|
+ void speedChange(unsigned cycleCounter);
|
|
+ uint_least32_t * spPalette() { return p_.spPalette; }
|
|
+ void update(unsigned cc);
|
|
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ p_.loadOrSave(state);
|
|
+ }
|
|
private:
|
|
PPUPriv p_;
|
|
};
|
|
diff --git a/libgambatte/src/video/sprite_mapper.cpp b/libgambatte/src/video/sprite_mapper.cpp
|
|
index 05ec6a8..ec1536e 100644
|
|
--- a/libgambatte/src/video/sprite_mapper.cpp
|
|
+++ b/libgambatte/src/video/sprite_mapper.cpp
|
|
@@ -39,6 +39,10 @@ private:
|
|
|
|
}
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
namespace gambatte {
|
|
|
|
SpriteMapper::OamReader::OamReader(LyCounter const &lyCounter, unsigned char const *oamram)
|
|
@@ -65,7 +69,7 @@ void SpriteMapper::OamReader::reset(unsigned char const *const oamram, bool cons
|
|
}
|
|
}
|
|
|
|
-static unsigned toPosCycles(unsigned long const cc, LyCounter const &lyCounter) {
|
|
+static unsigned toPosCycles(unsigned const cc, LyCounter const &lyCounter) {
|
|
unsigned lc = lyCounter.lineCycles(cc) + 3 - lyCounter.isDoubleSpeed() * 3u;
|
|
if (lc >= 456)
|
|
lc -= 456;
|
|
@@ -73,7 +77,7 @@ static unsigned toPosCycles(unsigned long const cc, LyCounter const &lyCounter)
|
|
return lc;
|
|
}
|
|
|
|
-void SpriteMapper::OamReader::update(unsigned long const cc) {
|
|
+void SpriteMapper::OamReader::update(unsigned const cc) {
|
|
if (cc > lu_) {
|
|
if (changed()) {
|
|
unsigned const lulc = toPosCycles(lu_, lyCounter_);
|
|
@@ -115,7 +119,7 @@ void SpriteMapper::OamReader::update(unsigned long const cc) {
|
|
}
|
|
}
|
|
|
|
-void SpriteMapper::OamReader::change(unsigned long cc) {
|
|
+void SpriteMapper::OamReader::change(unsigned cc) {
|
|
update(cc);
|
|
lastChange_ = std::min(toPosCycles(lu_, lyCounter_), 80u);
|
|
}
|
|
@@ -132,7 +136,7 @@ void SpriteMapper::OamReader::loadState(SaveState const &ss, unsigned char const
|
|
change(lu_);
|
|
}
|
|
|
|
-void SpriteMapper::OamReader::enableDisplay(unsigned long cc) {
|
|
+void SpriteMapper::OamReader::enableDisplay(unsigned cc) {
|
|
std::memset(buf_, 0x00, sizeof buf_);
|
|
std::fill(szbuf_, szbuf_ + 40, false);
|
|
lu_ = cc + (80 << lyCounter_.isDoubleSpeed());
|
|
@@ -145,6 +149,7 @@ SpriteMapper::SpriteMapper(NextM0Time &nextM0Time,
|
|
: nextM0Time_(nextM0Time)
|
|
, oamReader_(lyCounter, oamram)
|
|
{
|
|
+ memset(spritemap_, 0, sizeof(spritemap_));
|
|
clearMap();
|
|
}
|
|
|
|
@@ -188,12 +193,12 @@ void SpriteMapper::sortLine(unsigned const ly) const {
|
|
SpxLess(posbuf() + 1));
|
|
}
|
|
|
|
-unsigned long SpriteMapper::doEvent(unsigned long const time) {
|
|
+unsigned SpriteMapper::doEvent(unsigned const time) {
|
|
oamReader_.update(time);
|
|
mapSprites();
|
|
return oamReader_.changed()
|
|
? time + oamReader_.lineTime()
|
|
- : static_cast<unsigned long>(disabled_time);
|
|
+ : static_cast<unsigned>(disabled_time);
|
|
}
|
|
|
|
}
|
|
diff --git a/libgambatte/src/video/sprite_mapper.h b/libgambatte/src/video/sprite_mapper.h
|
|
index 7d8dbe1..341bce6 100644
|
|
--- a/libgambatte/src/video/sprite_mapper.h
|
|
+++ b/libgambatte/src/video/sprite_mapper.h
|
|
@@ -19,8 +19,13 @@
|
|
#ifndef SPRITE_MAPPER_H
|
|
#define SPRITE_MAPPER_H
|
|
|
|
+//
|
|
+// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
|
|
+// - Make it rerecording-friendly.
|
|
+
|
|
#include "ly_counter.h"
|
|
#include "../savestate.h"
|
|
+#include "../loadsave.h"
|
|
|
|
namespace gambatte {
|
|
|
|
@@ -32,17 +37,17 @@ public:
|
|
LyCounter const &lyCounter,
|
|
unsigned char const *oamram);
|
|
void reset(unsigned char const *oamram, bool cgb);
|
|
- unsigned long doEvent(unsigned long time);
|
|
+ unsigned doEvent(unsigned time);
|
|
bool largeSprites(unsigned spNo) const { return oamReader_.largeSprites(spNo); }
|
|
unsigned numSprites(unsigned ly) const { return num_[ly] & ~need_sorting_mask; }
|
|
- void oamChange(unsigned long cc) { oamReader_.change(cc); }
|
|
- void oamChange(unsigned char const *oamram, unsigned long cc) { oamReader_.change(oamram, cc); }
|
|
+ void oamChange(unsigned cc) { oamReader_.change(cc); }
|
|
+ void oamChange(unsigned char const *oamram, unsigned cc) { oamReader_.change(oamram, cc); }
|
|
unsigned char const * oamram() const { return oamReader_.oam(); }
|
|
unsigned char const * posbuf() const { return oamReader_.spritePosBuf(); }
|
|
- void preSpeedChange(unsigned long cc) { oamReader_.update(cc); }
|
|
- void postSpeedChange(unsigned long cc) { oamReader_.change(cc); }
|
|
+ void preSpeedChange(unsigned cc) { oamReader_.update(cc); }
|
|
+ void postSpeedChange(unsigned cc) { oamReader_.change(cc); }
|
|
|
|
- void resetCycleCounter(unsigned long oldCc, unsigned long newCc) {
|
|
+ void resetCycleCounter(unsigned oldCc, unsigned newCc) {
|
|
oamReader_.update(oldCc);
|
|
oamReader_.resetCycleCounter(oldCc, newCc);
|
|
}
|
|
@@ -57,7 +62,7 @@ public:
|
|
}
|
|
|
|
void setStatePtrs(SaveState &state) { oamReader_.setStatePtrs(state); }
|
|
- void enableDisplay(unsigned long cc) { oamReader_.enableDisplay(cc); }
|
|
+ void enableDisplay(unsigned cc) { oamReader_.enableDisplay(cc); }
|
|
void saveState(SaveState &state) const { oamReader_.saveState(state); }
|
|
|
|
void loadState(SaveState const &state, unsigned char const *oamram) {
|
|
@@ -65,33 +70,48 @@ public:
|
|
mapSprites();
|
|
}
|
|
|
|
- bool inactivePeriodAfterDisplayEnable(unsigned long cc) const {
|
|
+ bool inactivePeriodAfterDisplayEnable(unsigned cc) const {
|
|
return oamReader_.inactivePeriodAfterDisplayEnable(cc);
|
|
}
|
|
|
|
- static unsigned long schedule(LyCounter const &lyCounter, unsigned long cc) {
|
|
+ static unsigned schedule(LyCounter const &lyCounter, unsigned cc) {
|
|
return lyCounter.nextLineCycle(80, cc);
|
|
}
|
|
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ state(spritemap_, 1440);
|
|
+ state(num_, 144);
|
|
+ oamReader_.loadOrSave(state);
|
|
+ }
|
|
private:
|
|
class OamReader {
|
|
public:
|
|
+ void loadOrSave(loadsave& state) {
|
|
+ state(buf_, 80);
|
|
+ for(unsigned i = 0; i < 40; i++)
|
|
+ state(szbuf_[i]);
|
|
+ state(lu_);
|
|
+ state(lastChange_);
|
|
+ state(largeSpritesSrc_);
|
|
+ state(cgb_);
|
|
+ }
|
|
+
|
|
OamReader(LyCounter const &lyCounter, unsigned char const *oamram);
|
|
void reset(unsigned char const *oamram, bool cgb);
|
|
- void change(unsigned long cc);
|
|
- void change(unsigned char const *oamram, unsigned long cc) { change(cc); oamram_ = oamram; }
|
|
+ void change(unsigned cc);
|
|
+ void change(unsigned char const *oamram, unsigned cc) { change(cc); oamram_ = oamram; }
|
|
bool changed() const { return lastChange_ != 0xFF; }
|
|
bool largeSprites(unsigned spNo) const { return szbuf_[spNo]; }
|
|
unsigned char const * oam() const { return oamram_; }
|
|
- void resetCycleCounter(unsigned long oldCc, unsigned long newCc) { lu_ -= oldCc - newCc; }
|
|
+ void resetCycleCounter(unsigned oldCc, unsigned newCc) { lu_ -= oldCc - newCc; }
|
|
void setLargeSpritesSrc(bool src) { largeSpritesSrc_ = src; }
|
|
- void update(unsigned long cc);
|
|
+ void update(unsigned cc);
|
|
unsigned char const * spritePosBuf() const { return buf_; }
|
|
void setStatePtrs(SaveState &state);
|
|
- void enableDisplay(unsigned long cc);
|
|
+ void enableDisplay(unsigned cc);
|
|
void saveState(SaveState &state) const { state.ppu.enableDisplayM0Time = lu_; }
|
|
void loadState(SaveState const &ss, unsigned char const *oamram);
|
|
- bool inactivePeriodAfterDisplayEnable(unsigned long cc) const { return cc < lu_; }
|
|
+ bool inactivePeriodAfterDisplayEnable(unsigned cc) const { return cc < lu_; }
|
|
unsigned lineTime() const { return lyCounter_.lineTime(); }
|
|
|
|
private:
|
|
@@ -99,7 +119,7 @@ private:
|
|
bool szbuf_[40];
|
|
LyCounter const &lyCounter_;
|
|
unsigned char const *oamram_;
|
|
- unsigned long lu_;
|
|
+ unsigned lu_;
|
|
unsigned char lastChange_;
|
|
bool largeSpritesSrc_;
|
|
bool cgb_;
|
|
@@ -115,6 +135,7 @@ private:
|
|
void clearMap();
|
|
void mapSprites();
|
|
void sortLine(unsigned ly) const;
|
|
+
|
|
};
|
|
|
|
}
|
|
--
|
|
1.8.5
|
|
|