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/9] 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;
+
 };
 
 }
-- 
2.1.3

