Delay committing fullscreen until seeing window size change
[lsnes.git] / libgambatte-patches / svn537 / 0001-Changes-to-make-libgambatte-rerecording-friendly.patch
blob1ff3ecb3d270c16372a24458d8f6fb6b48fde8dd
1 From 148f2f6e1142f9d2caa9612dd9a68069426537f8 Mon Sep 17 00:00:00 2001
2 From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
3 Date: Fri, 9 Aug 2013 20:13:11 +0300
4 Subject: [PATCH 1/9] Changes to make libgambatte rerecording friendly
6 ---
7 Makefile | 10 +
8 libgambatte/Makefile | 18 ++
9 libgambatte/include/gambatte.h | 68 ++++++-
10 libgambatte/src/bitmap_font.cpp | 10 +-
11 libgambatte/src/bitmap_font.h | 6 +-
12 libgambatte/src/cpu.cpp | 42 ++++-
13 libgambatte/src/cpu.h | 27 ++-
14 libgambatte/src/file/file.cpp | 34 ++++
15 libgambatte/src/file/file.h | 10 +
16 libgambatte/src/gambatte.cpp | 127 +++++++++++--
17 libgambatte/src/initstate.cpp | 8 +-
18 libgambatte/src/initstate.h | 8 +-
19 libgambatte/src/interrupter.cpp | 17 +-
20 libgambatte/src/interrupter.h | 17 +-
21 libgambatte/src/interruptrequester.cpp | 23 ++-
22 libgambatte/src/interruptrequester.h | 23 ++-
23 libgambatte/src/loadsave.cpp | 266 +++++++++++++++++++++++++++
24 libgambatte/src/loadsave.h | 160 ++++++++++++++++
25 libgambatte/src/mem/cartridge.cpp | 159 +++++++++++++---
26 libgambatte/src/mem/cartridge.h | 51 +++--
27 libgambatte/src/mem/memptrs.cpp | 38 +++-
28 libgambatte/src/mem/memptrs.h | 8 +
29 libgambatte/src/mem/rtc.cpp | 56 +++++-
30 libgambatte/src/mem/rtc.h | 12 +-
31 libgambatte/src/memory.cpp | 104 +++++++----
32 libgambatte/src/memory.h | 87 +++++----
33 libgambatte/src/minkeeper.h | 29 ++-
34 libgambatte/src/savestate.h | 47 ++---
35 libgambatte/src/sound.cpp | 33 +++-
36 libgambatte/src/sound.h | 20 +-
37 libgambatte/src/sound/channel1.cpp | 45 ++++-
38 libgambatte/src/sound/channel1.h | 29 ++-
39 libgambatte/src/sound/channel2.cpp | 40 +++-
40 libgambatte/src/sound/channel2.h | 16 +-
41 libgambatte/src/sound/channel3.cpp | 41 ++++-
42 libgambatte/src/sound/channel3.h | 26 ++-
43 libgambatte/src/sound/channel4.cpp | 59 ++++--
44 libgambatte/src/sound/channel4.h | 39 ++--
45 libgambatte/src/sound/duty_unit.cpp | 34 +++-
46 libgambatte/src/sound/duty_unit.h | 27 ++-
47 libgambatte/src/sound/envelope_unit.cpp | 19 +-
48 libgambatte/src/sound/envelope_unit.h | 12 +-
49 libgambatte/src/sound/length_counter.cpp | 19 +-
50 libgambatte/src/sound/length_counter.h | 12 +-
51 libgambatte/src/sound/sound_unit.h | 15 +-
52 libgambatte/src/sound/static_output_tester.h | 8 +-
53 libgambatte/src/state_osd_elements.cpp | 8 +-
54 libgambatte/src/statesaver.cpp | 4 +-
55 libgambatte/src/statesaver.h | 5 +
56 libgambatte/src/tima.cpp | 35 ++--
57 libgambatte/src/tima.h | 28 +--
58 libgambatte/src/video.cpp | 146 ++++++++-------
59 libgambatte/src/video.h | 123 +++++++------
60 libgambatte/src/video/ly_counter.cpp | 14 +-
61 libgambatte/src/video/ly_counter.h | 26 ++-
62 libgambatte/src/video/lyc_irq.cpp | 16 +-
63 libgambatte/src/video/lyc_irq.h | 27 ++-
64 libgambatte/src/video/m0_irq.h | 9 +-
65 libgambatte/src/video/next_m0_time.h | 9 +
66 libgambatte/src/video/ppu.cpp | 120 +++++++++---
67 libgambatte/src/video/ppu.h | 92 ++++++---
68 libgambatte/src/video/sprite_mapper.cpp | 17 +-
69 libgambatte/src/video/sprite_mapper.h | 53 ++++--
70 63 files changed, 2099 insertions(+), 592 deletions(-)
71 create mode 100644 Makefile
72 create mode 100644 libgambatte/Makefile
73 create mode 100644 libgambatte/src/loadsave.cpp
74 create mode 100644 libgambatte/src/loadsave.h
76 diff --git a/Makefile b/Makefile
77 new file mode 100644
78 index 0000000..2714a5b
79 --- /dev/null
80 +++ b/Makefile
81 @@ -0,0 +1,10 @@
82 +all: libgambatte/__all_files__
84 +libgambatte/__all_files__: forcelook
85 + $(MAKE) -C libgambatte
87 +clean: forcelook
88 + $(MAKE) -C libgambatte clean
90 +forcelook:
91 + @true
92 diff --git a/libgambatte/Makefile b/libgambatte/Makefile
93 new file mode 100644
94 index 0000000..7c3724e
95 --- /dev/null
96 +++ b/libgambatte/Makefile
97 @@ -0,0 +1,18 @@
98 +all: libgambatte.$(ARCHIVE_SUFFIX)
100 +REALAR=$(CROSS_PREFIX)ar
102 +OBJECTS=$(patsubst %.cpp,%.$(OBJECT_SUFFIX),$(wildcard src/*.cpp src/video/*.cpp src/mem/*.cpp src/sound/*.cpp src/file/file.cpp))
104 +%.o: %.cpp
105 + $(gambatte_compiler) $(CFLAGS) -Wno-deprecated-declarations -DHAVE_CSTDINT -I../common -Iinclude -Isrc -c -o $@ $<
107 +libgambatte.$(ARCHIVE_SUFFIX): $(OBJECTS)
108 + $(REALAR) crvs $@ $^
109 + $(REALRANLIB) $@
111 +clean: forcelook
112 + rm -f $(OBJECTS) libgambatte.$(ARCHIVE_SUFFIX)
114 +forcelook:
115 + @true
116 \ No newline at end of file
117 diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h
118 index f1a4633..2901fdf 100644
119 --- a/libgambatte/include/gambatte.h
120 +++ b/libgambatte/include/gambatte.h
121 @@ -24,6 +24,11 @@
122 #include "loadres.h"
123 #include <cstddef>
124 #include <string>
125 +#include <vector>
128 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
129 +// - Make it rerecording-friendly.
131 namespace gambatte {
133 @@ -52,6 +57,15 @@ public:
135 LoadRes load(std::string const &romfile, unsigned flags = 0);
137 + /** Load ROM image.
139 + * @param image Raw ROM image data.
140 + * @param isize Size of raw ROM image data.
141 + * @param flags ORed combination of LoadFlags.
142 + * @return 0 on success, negative value on failure.
143 + */
144 + LoadRes load(const unsigned char* image, size_t isize, unsigned flags = 0);
147 * Emulates until at least 'samples' audio samples are produced in the
148 * supplied audio buffer, or until a video frame has been drawn.
149 @@ -80,8 +94,8 @@ public:
150 * @return sample offset in audioBuf at which the video frame was completed, or -1
151 * if no new video frame was completed.
153 - std::ptrdiff_t runFor(gambatte::uint_least32_t *videoBuf, std::ptrdiff_t pitch,
154 - gambatte::uint_least32_t *audioBuf, std::size_t &samples);
155 + signed runFor(gambatte::uint_least32_t *videoBuf, std::ptrdiff_t pitch,
156 + gambatte::uint_least32_t *soundBuf, unsigned &samples);
159 * Reset to initial state.
160 @@ -93,7 +107,7 @@ public:
161 * @param palNum 0 <= palNum < 3. One of BG_PALETTE, SP1_PALETTE and SP2_PALETTE.
162 * @param colorNum 0 <= colorNum < 4
164 - void setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32);
165 + void setDmgPaletteColor(int palNum, int colorNum, uint_least32_t rgb32);
167 /** Sets the callback used for getting input state. */
168 void setInputGetter(InputGetter *getInput);
169 @@ -149,6 +163,16 @@ public:
171 bool loadState(std::string const &filepath);
173 + /** Save savestate to given buffer.
174 + */
175 + void saveState(std::vector<char>& data, const std::vector<char>& cmpdata);
176 + /** Save savestate to given buffer.
177 + */
178 + void saveState(std::vector<char>& data);
179 + /** Load savestate from given buffer.
180 + */
181 + void loadState(const std::vector<char>& data);
184 * Selects which state slot to save state to or load state from.
185 * There are 10 such slots, numbered from 0 to 9 (periodically extended for all n).
186 @@ -180,9 +204,45 @@ public:
188 void setGameShark(std::string const &codes);
190 + /** Set RTC base time.
191 + */
192 + void setRtcBase(time_t time);
194 + /** Get RTC base time.
195 + */
196 + time_t getRtcBase();
198 + /** Get pointer and size to Work RAM.
199 + * @return The pointer and size of Work RAM.
200 + */
201 + std::pair<unsigned char*, size_t> getWorkRam();
203 + /** Get pointer and size to Save RAM.
204 + * @return The pointer and size of Save RAM.
205 + */
206 + std::pair<unsigned char*, size_t> getSaveRam();
208 + /** Get pointer and size to I/O RAM.
209 + * @return The pointer and size of I/O RAM.
210 + */
211 + std::pair<unsigned char*, size_t> getIoRam();
213 + /** Get pointer and size to Video RAM.
214 + * @return The pointer and size of Video RAM.
215 + */
216 + std::pair<unsigned char*, size_t> getVideoRam();
218 + /** Function to get wall time. */
219 + void set_walltime_fn(time_t (*_walltime)());
221 + /** Get version. */
222 + static std::string version();
223 private:
224 + void preload_common();
225 + void postload_common(const unsigned flags);
226 struct Priv;
227 Priv *const p_;
228 + time_t (*walltime)();
230 GB(GB const &);
231 GB & operator=(GB const &);
232 @@ -190,4 +250,6 @@ private:
236 +#define GAMBATTE_USES_LOADRES
238 #endif
239 diff --git a/libgambatte/src/bitmap_font.cpp b/libgambatte/src/bitmap_font.cpp
240 index 614f94e..aec5d2e 100644
241 --- a/libgambatte/src/bitmap_font.cpp
242 +++ b/libgambatte/src/bitmap_font.cpp
243 @@ -68,6 +68,10 @@
244 gnome dot org.
248 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
249 +// - Make it rerecording-friendly.
251 #include "bitmap_font.h"
252 #include <algorithm>
254 @@ -288,7 +292,7 @@ namespace {
256 class Rgb32Fill {
257 public:
258 - explicit Rgb32Fill(unsigned long color)
259 + explicit Rgb32Fill(uint_least32_t color)
260 : color_(color)
263 @@ -298,12 +302,12 @@ public:
266 private:
267 - unsigned long const color_;
268 + uint_least32_t const color_;
273 -void print(gambatte::uint_least32_t *dest, std::ptrdiff_t pitch, unsigned long color, char const *chars) {
274 +void print(gambatte::uint_least32_t *dest, std::ptrdiff_t pitch, uint_least32_t color, char const *chars) {
275 print(dest, pitch, Rgb32Fill(color), chars);
278 diff --git a/libgambatte/src/bitmap_font.h b/libgambatte/src/bitmap_font.h
279 index db83db8..81bc5d0 100644
280 --- a/libgambatte/src/bitmap_font.h
281 +++ b/libgambatte/src/bitmap_font.h
282 @@ -19,6 +19,10 @@
283 #ifndef BITMAP_FONT_H
284 #define BITMAP_FONT_H
287 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
288 +// - Make it rerecording-friendly.
290 #include "gbint.h"
291 #include <cstddef>
293 @@ -44,7 +48,7 @@ std::size_t getWidth(char const *chars);
294 template<class RandomAccessIterator, class Fill>
295 void print(RandomAccessIterator dest, std::ptrdiff_t pitch, Fill fill, char const *chars);
297 -void print(gambatte::uint_least32_t *dest, std::ptrdiff_t pitch, unsigned long color, char const *chars);
298 +void print(gambatte::uint_least32_t *dest, std::ptrdiff_t pitch, uint_least32_t color, char const *chars);
299 void utoa(unsigned u, char *a);
301 // --- INTERFACE END ---
302 diff --git a/libgambatte/src/cpu.cpp b/libgambatte/src/cpu.cpp
303 index fee943a..06400c5 100644
304 --- a/libgambatte/src/cpu.cpp
305 +++ b/libgambatte/src/cpu.cpp
306 @@ -20,10 +20,14 @@
307 #include "memory.h"
308 #include "savestate.h"
311 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
312 +// - Make it rerecording-friendly.
314 namespace gambatte {
316 -CPU::CPU()
317 -: mem_(Interrupter(sp, pc_))
318 +CPU::CPU(time_t (**_getCurrentTime)())
319 +: mem_(Interrupter(sp, pc_), _getCurrentTime)
320 , cycleCounter_(0)
321 , pc_(0x100)
322 , sp(0xFFFE)
323 @@ -42,10 +46,10 @@ CPU::CPU()
327 -long CPU::runFor(unsigned long const cycles) {
328 +signed CPU::runFor(unsigned const cycles) {
329 process(cycles);
331 - long const csb = mem_.cyclesSinceBlit(cycleCounter_);
332 + signed const csb = mem_.cyclesSinceBlit(cycleCounter_);
334 if (cycleCounter_ & 0x80000000)
335 cycleCounter_ = mem_.resetCounters(cycleCounter_);
336 @@ -121,6 +125,26 @@ void CPU::loadState(SaveState const &state) {
337 skip_ = state.cpu.skip;
340 +void CPU::loadOrSave(loadsave& state)
342 + mem_.loadOrSave(state);
343 + state(cycleCounter_);
344 + state(pc_);
345 + state(sp);
346 + state(hf1);
347 + state(hf2);
348 + state(zf);
349 + state(cf);
350 + state(a_);
351 + state(b);
352 + state(c);
353 + state(d);
354 + state(e);
355 + state(h);
356 + state(l);
357 + state(skip_);
360 // The main reasons for the use of macros is to more conveniently be able to tweak
361 // which variables are local and which are not, combined with the fact that at the
362 // time they were written GCC had a tendency to not be able to keep hot variables
363 @@ -485,18 +509,18 @@ void CPU::loadState(SaveState const &state) {
364 PC_MOD(high << 8 | low); \
365 } while (0)
367 -void CPU::process(unsigned long const cycles) {
368 +void CPU::process(unsigned const cycles) {
369 mem_.setEndtime(cycleCounter_, cycles);
371 unsigned char a = a_;
372 - unsigned long cycleCounter = cycleCounter_;
373 + unsigned cycleCounter = cycleCounter_;
375 while (mem_.isActive()) {
376 unsigned short pc = pc_;
378 if (mem_.halted()) {
379 if (cycleCounter < mem_.nextEventTime()) {
380 - unsigned long cycles = mem_.nextEventTime() - cycleCounter;
381 + unsigned cycles = mem_.nextEventTime() - cycleCounter;
382 cycleCounter += cycles + (-cycles & 3);
384 } else while (cycleCounter < mem_.nextEventTime()) {
385 @@ -591,7 +615,7 @@ void CPU::process(unsigned long const cycles) {
386 cycleCounter = mem_.stop(cycleCounter);
388 if (cycleCounter < mem_.nextEventTime()) {
389 - unsigned long cycles = mem_.nextEventTime() - cycleCounter;
390 + unsigned cycles = mem_.nextEventTime() - cycleCounter;
391 cycleCounter += cycles + (-cycles & 3);
394 @@ -1005,7 +1029,7 @@ void CPU::process(unsigned long const cycles) {
395 mem_.halt();
397 if (cycleCounter < mem_.nextEventTime()) {
398 - unsigned long cycles = mem_.nextEventTime() - cycleCounter;
399 + unsigned cycles = mem_.nextEventTime() - cycleCounter;
400 cycleCounter += cycles + (-cycles & 3);
403 diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h
404 index 01b82b9..9f9a11e 100644
405 --- a/libgambatte/src/cpu.h
406 +++ b/libgambatte/src/cpu.h
407 @@ -19,16 +19,22 @@
408 #ifndef CPU_H
409 #define CPU_H
412 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
413 +// - Make it rerecording-friendly.
415 #include "memory.h"
416 +#include "loadsave.h"
418 namespace gambatte {
420 class CPU {
421 public:
422 - CPU();
423 - long runFor(unsigned long cycles);
424 + CPU(time_t (**_getCurrentTime)());
425 + signed runFor(unsigned cycles);
426 void setStatePtrs(SaveState &state);
427 void saveState(SaveState &state);
428 + void loadOrSave(loadsave& state);
429 void loadState(SaveState const &state);
430 void loadSavedata() { mem_.loadSavedata(); }
431 void saveSavedata() { mem_.saveSavedata(); }
432 @@ -57,6 +63,10 @@ public:
433 return mem_.loadROM(romfile, forceDmg, multicartCompat);
436 + LoadRes load(const unsigned char* image, size_t isize, bool forceDmg, bool multicartCompat) {
437 + return mem_.loadROM(image, isize, forceDmg, multicartCompat);
440 bool loaded() const { return mem_.loaded(); }
441 char const * romTitle() const { return mem_.romTitle(); }
442 PakInfo const pakInfo(bool multicartCompat) const { return mem_.pakInfo(multicartCompat); }
443 @@ -64,23 +74,30 @@ public:
444 std::size_t fillSoundBuffer() { return mem_.fillSoundBuffer(cycleCounter_); }
445 bool isCgb() const { return mem_.isCgb(); }
447 - void setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32) {
448 + void setDmgPaletteColor(int palNum, int colorNum, uint_least32_t rgb32) {
449 mem_.setDmgPaletteColor(palNum, colorNum, rgb32);
452 void setGameGenie(std::string const &codes) { mem_.setGameGenie(codes); }
453 void setGameShark(std::string const &codes) { mem_.setGameShark(codes); }
455 + void setRtcBase(time_t time) { mem_.setRtcBase(time); }
456 + time_t getRtcBase() { return mem_.getRtcBase(); }
457 + std::pair<unsigned char*, size_t> getWorkRam() { return mem_.getWorkRam(); }
458 + std::pair<unsigned char*, size_t> getSaveRam() { return mem_.getSaveRam(); }
459 + std::pair<unsigned char*, size_t> getIoRam() { return mem_.getIoRam(); }
460 + std::pair<unsigned char*, size_t> getVideoRam() { return mem_.getVideoRam(); };
462 private:
463 Memory mem_;
464 - unsigned long cycleCounter_;
465 + unsigned cycleCounter_;
466 unsigned short pc_;
467 unsigned short sp;
468 unsigned hf1, hf2, zf, cf;
469 unsigned char a_, b, c, d, e, /*f,*/ h, l;
470 bool skip_;
472 - void process(unsigned long cycles);
473 + void process(unsigned cycles);
477 diff --git a/libgambatte/src/file/file.cpp b/libgambatte/src/file/file.cpp
478 index e6922b2..130e0e2 100644
479 --- a/libgambatte/src/file/file.cpp
480 +++ b/libgambatte/src/file/file.cpp
481 @@ -20,7 +20,41 @@ Free Software Foundation, Inc.,
482 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
483 ***************************************************************************/
484 #include "stdfile.h"
485 +#include <cstring>
488 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
489 +// - Make it rerecording-friendly.
491 transfer_ptr<gambatte::File> gambatte::newFileInstance(std::string const &filepath) {
492 return transfer_ptr<File>(new StdFile(filepath.c_str()));
495 +namespace
497 + struct MemoryFile : public gambatte::File
499 + MemoryFile(const unsigned char* image, size_t isize) : buf(image), bufsize(isize),
500 + ptr(0), xfail(false) {}
501 + ~MemoryFile() {}
502 + void rewind() { ptr = 0; xfail = false; }
503 + std::size_t size() const { return bufsize; }
504 + void read(char *buffer, std::size_t amount) {
505 + if(amount > bufsize - ptr) {
506 + memcpy(buffer, buf, bufsize - ptr);
507 + xfail = true;
508 + } else
509 + memcpy(buffer, buf, amount);
511 + bool fail() const { return xfail; }
512 + private:
513 + const unsigned char* buf;
514 + size_t bufsize;
515 + size_t ptr;
516 + bool xfail;
517 + };
520 +transfer_ptr<gambatte::File> gambatte::newFileInstance(const unsigned char* image, size_t isize) {
521 + return transfer_ptr<File>(new MemoryFile(image, isize));
523 diff --git a/libgambatte/src/file/file.h b/libgambatte/src/file/file.h
524 index efde793..ed04461 100644
525 --- a/libgambatte/src/file/file.h
526 +++ b/libgambatte/src/file/file.h
527 @@ -22,6 +22,15 @@ Free Software Foundation, Inc.,
528 #ifndef GAMBATTE_FILE_H
529 #define GAMBATTE_FILE_H
533 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
534 +// - Make it rerecording-friendly.
536 +// Modified 2012-07-10 by H. Ilari Liusvaara
537 +// - New API methods.
539 +#include <memory>
540 #include "transfer_ptr.h"
541 #include <string>
543 @@ -37,6 +46,7 @@ public:
546 transfer_ptr<File> newFileInstance(std::string const &filepath);
547 +transfer_ptr<File> newFileInstance(const unsigned char* image, size_t isize);
551 diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp
552 index ffe35b3..0204557 100644
553 --- a/libgambatte/src/gambatte.cpp
554 +++ b/libgambatte/src/gambatte.cpp
555 @@ -25,6 +25,10 @@
556 #include <cstring>
557 #include <sstream>
560 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
561 +// - Make it rerecording-friendly.
563 static std::string const itos(int i) {
564 std::stringstream ss;
565 ss << i;
566 @@ -35,6 +39,14 @@ static std::string const statePath(std::string const &basePath, int stateNo) {
567 return basePath + "_" + itos(stateNo) + ".gqs";
570 +namespace
572 + time_t default_walltime()
574 + return time(0);
578 namespace gambatte {
580 struct GB::Priv {
581 @@ -42,10 +54,10 @@ struct GB::Priv {
582 int stateNo;
583 unsigned loadflags;
585 - Priv() : stateNo(1), loadflags(0) {}
586 + Priv(time_t (**_getCurrentTime)()) : stateNo(1), loadflags(0), cpu(_getCurrentTime) {}
589 -GB::GB() : p_(new Priv) {}
590 +GB::GB() : p_(new Priv(&walltime)), walltime(default_walltime) {}
592 GB::~GB() {
593 if (p_->cpu.loaded())
594 @@ -54,8 +66,8 @@ GB::~GB() {
595 delete p_;
598 -std::ptrdiff_t GB::runFor(gambatte::uint_least32_t *const videoBuf, std::ptrdiff_t const pitch,
599 - gambatte::uint_least32_t *const soundBuf, std::size_t &samples) {
600 +signed GB::runFor(gambatte::uint_least32_t *const videoBuf, std::ptrdiff_t const pitch,
601 + gambatte::uint_least32_t *const soundBuf, unsigned &samples) {
602 if (!p_->cpu.loaded()) {
603 samples = 0;
604 return -1;
605 @@ -64,10 +76,10 @@ std::ptrdiff_t GB::runFor(gambatte::uint_least32_t *const videoBuf, std::ptrdiff
606 p_->cpu.setVideoBuffer(videoBuf, pitch);
607 p_->cpu.setSoundBuffer(soundBuf);
609 - long const cyclesSinceBlit = p_->cpu.runFor(samples * 2);
610 + signed const cyclesSinceBlit = p_->cpu.runFor(samples * 2);
611 samples = p_->cpu.fillSoundBuffer();
612 return cyclesSinceBlit >= 0
613 - ? static_cast<std::ptrdiff_t>(samples) - (cyclesSinceBlit >> 1)
614 + ? static_cast<signed>(samples) - (cyclesSinceBlit >> 1)
615 : cyclesSinceBlit;
618 @@ -77,7 +89,7 @@ void GB::reset() {
620 SaveState state;
621 p_->cpu.setStatePtrs(state);
622 - setInitState(state, p_->cpu.isCgb(), p_->loadflags & GBA_CGB);
623 + setInitState(state, p_->cpu.isCgb(), p_->loadflags & GBA_CGB, walltime());
624 p_->cpu.loadState(state);
625 p_->cpu.loadSavedata();
627 @@ -91,24 +103,44 @@ void GB::setSaveDir(std::string const &sdir) {
628 p_->cpu.setSaveDir(sdir);
631 -LoadRes GB::load(std::string const &romfile, unsigned const flags) {
632 +void GB::preload_common()
634 if (p_->cpu.loaded())
635 p_->cpu.saveSavedata();
638 +void GB::postload_common(const unsigned flags)
640 + SaveState state;
641 + p_->cpu.setStatePtrs(state);
642 + setInitState(state, p_->cpu.isCgb(), flags & GBA_CGB, walltime());
643 + p_->cpu.loadState(state);
644 + p_->cpu.loadSavedata();
646 + p_->stateNo = 1;
647 + p_->cpu.setOsdElement(transfer_ptr<OsdElement>());
650 +LoadRes GB::load(std::string const &romfile, unsigned const flags) {
651 + preload_common();
653 LoadRes const loadres = p_->cpu.load(romfile,
654 flags & FORCE_DMG,
655 flags & MULTICART_COMPAT);
656 - if (loadres == LOADRES_OK) {
657 - SaveState state;
658 - p_->cpu.setStatePtrs(state);
659 - p_->loadflags = flags;
660 - setInitState(state, p_->cpu.isCgb(), flags & GBA_CGB);
661 - p_->cpu.loadState(state);
662 - p_->cpu.loadSavedata();
664 - p_->stateNo = 1;
665 - p_->cpu.setOsdElement(transfer_ptr<OsdElement>());
667 + if (loadres == LOADRES_OK)
668 + postload_common(flags);
670 + return loadres;
673 +LoadRes GB::load(const unsigned char* image, size_t isize, unsigned flags) {
674 + preload_common();
676 + LoadRes const loadres = p_->cpu.load(image, isize, flags & FORCE_DMG, flags & MULTICART_COMPAT);
678 + if (loadres == LOADRES_OK)
679 + postload_common(flags);
681 return loadres;
683 @@ -126,7 +158,7 @@ void GB::saveSavedata() {
684 p_->cpu.saveSavedata();
687 -void GB::setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32) {
688 +void GB::setDmgPaletteColor(int palNum, int colorNum, uint_least32_t rgb32) {
689 p_->cpu.setDmgPaletteColor(palNum, colorNum, rgb32);
692 @@ -176,6 +208,29 @@ bool GB::saveState(gambatte::uint_least32_t const *videoBuf, std::ptrdiff_t pitc
693 return false;
696 +void GB::saveState(std::vector<char>& data, const std::vector<char>& cmpdata) {
697 + if (p_->cpu.loaded()) {
698 + loadsave_save l(cmpdata);
699 + p_->cpu.loadOrSave(l);
700 + data = l.get();
704 +void GB::saveState(std::vector<char>& data) {
705 + if (p_->cpu.loaded()) {
706 + loadsave_save l;
707 + p_->cpu.loadOrSave(l);
708 + data = l.get();
712 +void GB::loadState(const std::vector<char>& data) {
713 + if (p_->cpu.loaded()) {
714 + loadsave_load l(data);
715 + p_->cpu.loadOrSave(l);
719 void GB::selectState(int n) {
720 n -= (n / 10) * 10;
721 p_->stateNo = n < 0 ? n + 10 : n;
722 @@ -209,4 +264,38 @@ void GB::setGameShark(std::string const &codes) {
723 p_->cpu.setGameShark(codes);
726 +void GB::setRtcBase(time_t time) {
727 + p_->cpu.setRtcBase(time);
730 +time_t GB::getRtcBase() {
731 + return p_->cpu.getRtcBase();
734 +std::pair<unsigned char*, size_t> GB::getWorkRam() {
735 + return p_->cpu.getWorkRam();
738 +std::pair<unsigned char*, size_t> GB::getSaveRam() {
739 + return p_->cpu.getSaveRam();
742 +std::pair<unsigned char*, size_t> GB::getIoRam() {
743 + return p_->cpu.getIoRam();
746 +std::pair<unsigned char*, size_t> GB::getVideoRam() {
747 + return p_->cpu.getVideoRam();
750 +void GB::set_walltime_fn(time_t (*_walltime)())
752 + walltime = _walltime;
755 +std::string GB::version()
757 + return "r537";
761 diff --git a/libgambatte/src/initstate.cpp b/libgambatte/src/initstate.cpp
762 index 2a31f44..496a7d2 100644
763 --- a/libgambatte/src/initstate.cpp
764 +++ b/libgambatte/src/initstate.cpp
765 @@ -24,6 +24,10 @@
766 #include <cstring>
767 #include <ctime>
770 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
771 +// - Make it rerecording-friendly.
773 namespace {
775 static void setInitialCgbWram(unsigned char *const wram) {
776 @@ -1147,7 +1151,7 @@ static void setInitialDmgIoamhram(unsigned char *const ioamhram) {
778 } // anon namespace
780 -void gambatte::setInitState(SaveState &state, bool const cgb, bool const gbaCgbMode) {
781 +void gambatte::setInitState(SaveState &state, bool const cgb, bool const gbaCgbMode, time_t starttime) {
782 static unsigned char const cgbObjpDump[0x40] = {
783 0x00, 0x00, 0xF2, 0xAB,
784 0x61, 0xC2, 0xD9, 0xBA,
785 @@ -1310,7 +1314,7 @@ void gambatte::setInitState(SaveState &state, bool const cgb, bool const gbaCgbM
786 state.spu.ch4.nr4 = 0;
787 state.spu.ch4.master = false;
789 - state.rtc.baseTime = std::time(0);
790 + state.rtc.baseTime = starttime;
791 state.rtc.haltTime = state.rtc.baseTime;
792 state.rtc.dataDh = 0;
793 state.rtc.dataDl = 0;
794 diff --git a/libgambatte/src/initstate.h b/libgambatte/src/initstate.h
795 index bdb33dd..f4d4a02 100644
796 --- a/libgambatte/src/initstate.h
797 +++ b/libgambatte/src/initstate.h
798 @@ -19,9 +19,15 @@
799 #ifndef INITSTATE_H
800 #define INITSTATE_H
803 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
804 +// - Make it rerecording-friendly.
806 +#include <ctime>
808 namespace gambatte {
810 -void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode);
811 +void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode, time_t starttime);
815 diff --git a/libgambatte/src/interrupter.cpp b/libgambatte/src/interrupter.cpp
816 index ac958f9..f0770a8 100644
817 --- a/libgambatte/src/interrupter.cpp
818 +++ b/libgambatte/src/interrupter.cpp
819 @@ -19,6 +19,10 @@
820 #include "interrupter.h"
821 #include "memory.h"
824 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
825 +// - Make it rerecording-friendly.
827 namespace gambatte {
829 Interrupter::Interrupter(unsigned short &sp, unsigned short &pc)
830 @@ -27,7 +31,7 @@ Interrupter::Interrupter(unsigned short &sp, unsigned short &pc)
834 -unsigned long Interrupter::interrupt(unsigned const address, unsigned long cc, Memory &memory) {
835 +unsigned Interrupter::interrupt(unsigned const address, unsigned cc, Memory &memory) {
836 cc += 8;
837 sp_ = (sp_ - 1) & 0xFFFF;
838 memory.write(sp_, pc_ >> 8, cc);
839 @@ -66,11 +70,20 @@ void Interrupter::setGameShark(std::string const &codes) {
843 -void Interrupter::applyVblankCheats(unsigned long const cc, Memory &memory) {
844 +void Interrupter::applyVblankCheats(unsigned const cc, Memory &memory) {
845 for (std::size_t i = 0, size = gsCodes_.size(); i < size; ++i) {
846 if (gsCodes_[i].type == 0x01)
847 memory.write(gsCodes_[i].address, gsCodes_[i].value, cc);
851 +void Interrupter::loadOrSave(loadsave& state) {
852 + unsigned gssize = gsCodes_.size();
853 + state(gssize);
854 + if(!state.saving())
855 + gsCodes_.resize(gssize);
856 + for(unsigned i = 0; i < gssize; i++)
857 + gsCodes_[i].loadOrSave(state);
861 diff --git a/libgambatte/src/interrupter.h b/libgambatte/src/interrupter.h
862 index fa7314d..328f7a8 100644
863 --- a/libgambatte/src/interrupter.h
864 +++ b/libgambatte/src/interrupter.h
865 @@ -19,8 +19,14 @@
866 #ifndef INTERRUPTER_H
867 #define INTERRUPTER_H
870 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
871 +// - Make it rerecording-friendly.
873 #include <string>
874 #include <vector>
875 +#include "loadsave.h"
878 namespace gambatte {
880 @@ -28,6 +34,12 @@ struct GsCode {
881 unsigned short address;
882 unsigned char value;
883 unsigned char type;
885 + void loadOrSave(loadsave& state) {
886 + state(address);
887 + state(value);
888 + state(type);
892 class Memory;
893 @@ -35,15 +47,16 @@ class Memory;
894 class Interrupter {
895 public:
896 Interrupter(unsigned short &sp, unsigned short &pc);
897 - unsigned long interrupt(unsigned address, unsigned long cycleCounter, Memory &memory);
898 + unsigned interrupt(unsigned address, unsigned cycleCounter, Memory &memory);
899 void setGameShark(std::string const &codes);
900 + void loadOrSave(loadsave& state);
902 private:
903 unsigned short &sp_;
904 unsigned short &pc_;
905 std::vector<GsCode> gsCodes_;
907 - void applyVblankCheats(unsigned long cc, Memory &mem);
908 + void applyVblankCheats(unsigned cc, Memory &mem);
912 diff --git a/libgambatte/src/interruptrequester.cpp b/libgambatte/src/interruptrequester.cpp
913 index 400733e..5091a81 100644
914 --- a/libgambatte/src/interruptrequester.cpp
915 +++ b/libgambatte/src/interruptrequester.cpp
916 @@ -19,6 +19,10 @@
917 #include "interruptrequester.h"
918 #include "savestate.h"
921 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
922 +// - Make it rerecording-friendly.
924 namespace gambatte {
926 InterruptRequester::InterruptRequester()
927 @@ -34,6 +38,15 @@ void InterruptRequester::saveState(SaveState &state) const {
928 state.mem.halted = halted();
931 +void InterruptRequester::loadOrSave(loadsave& state)
933 + eventTimes_.loadOrSave(state);
934 + state(minIntTime_);
935 + state(ifreg_);
936 + state(iereg_);
937 + intFlags_.loadOrSave(state);
940 void InterruptRequester::loadState(SaveState const &state) {
941 minIntTime_ = state.mem.minIntTime;
942 ifreg_ = state.mem.ioamhram.get()[0x10F];
943 @@ -42,17 +55,17 @@ void InterruptRequester::loadState(SaveState const &state) {
945 eventTimes_.setValue<intevent_interrupts>(intFlags_.imeOrHalted() && pendingIrqs()
946 ? minIntTime_
947 - : static_cast<unsigned long>(disabled_time));
948 + : static_cast<unsigned>(disabled_time));
951 -void InterruptRequester::resetCc(unsigned long oldCc, unsigned long newCc) {
952 +void InterruptRequester::resetCc(unsigned oldCc, unsigned newCc) {
953 minIntTime_ = minIntTime_ < oldCc ? 0 : minIntTime_ - (oldCc - newCc);
955 if (eventTimes_.value(intevent_interrupts) != disabled_time)
956 eventTimes_.setValue<intevent_interrupts>(minIntTime_);
959 -void InterruptRequester::ei(unsigned long cc) {
960 +void InterruptRequester::ei(unsigned cc) {
961 intFlags_.setIme();
962 minIntTime_ = cc + 1;
964 @@ -99,7 +112,7 @@ void InterruptRequester::setIereg(unsigned iereg) {
965 if (intFlags_.imeOrHalted()) {
966 eventTimes_.setValue<intevent_interrupts>(pendingIrqs()
967 ? minIntTime_
968 - : static_cast<unsigned long>(disabled_time));
969 + : static_cast<unsigned>(disabled_time));
973 @@ -109,7 +122,7 @@ void InterruptRequester::setIfreg(unsigned ifreg) {
974 if (intFlags_.imeOrHalted()) {
975 eventTimes_.setValue<intevent_interrupts>(pendingIrqs()
976 ? minIntTime_
977 - : static_cast<unsigned long>(disabled_time));
978 + : static_cast<unsigned>(disabled_time));
982 diff --git a/libgambatte/src/interruptrequester.h b/libgambatte/src/interruptrequester.h
983 index 24da184..0d423dc 100644
984 --- a/libgambatte/src/interruptrequester.h
985 +++ b/libgambatte/src/interruptrequester.h
986 @@ -19,11 +19,17 @@
987 #ifndef INTERRUPT_REQUESTER_H
988 #define INTERRUPT_REQUESTER_H
991 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
992 +// - Make it rerecording-friendly.
994 #include "counterdef.h"
995 #include "minkeeper.h"
996 +#include "loadsave.h"
998 namespace gambatte {
1001 struct SaveState;
1003 enum IntEventId { intevent_unhalt,
1004 @@ -41,12 +47,12 @@ public:
1005 InterruptRequester();
1006 void saveState(SaveState &) const;
1007 void loadState(SaveState const &);
1008 - void resetCc(unsigned long oldCc, unsigned long newCc);
1009 + void resetCc(unsigned oldCc, unsigned newCc);
1010 unsigned ifreg() const { return ifreg_; }
1011 unsigned pendingIrqs() const { return ifreg_ & iereg_; }
1012 bool ime() const { return intFlags_.ime(); }
1013 bool halted() const { return intFlags_.halted(); }
1014 - void ei(unsigned long cc);
1015 + void ei(unsigned cc);
1016 void di();
1017 void halt();
1018 void unhalt();
1019 @@ -54,12 +60,13 @@ public:
1020 void ackIrq(unsigned bit);
1021 void setIereg(unsigned iereg);
1022 void setIfreg(unsigned ifreg);
1023 + void loadOrSave(loadsave& state);
1025 IntEventId minEventId() const { return static_cast<IntEventId>(eventTimes_.min()); }
1026 - unsigned long minEventTime() const { return eventTimes_.minValue(); }
1027 - template<IntEventId id> void setEventTime(unsigned long value) { eventTimes_.setValue<id>(value); }
1028 - void setEventTime(IntEventId id, unsigned long value) { eventTimes_.setValue(id, value); }
1029 - unsigned long eventTime(IntEventId id) const { return eventTimes_.value(id); }
1030 + unsigned minEventTime() const { return eventTimes_.minValue(); }
1031 + template<IntEventId id> void setEventTime(unsigned value) { eventTimes_.setValue<id>(value); }
1032 + void setEventTime(IntEventId id, unsigned value) { eventTimes_.setValue(id, value); }
1033 + unsigned eventTime(IntEventId id) const { return eventTimes_.value(id); }
1035 private:
1036 class IntFlags {
1037 @@ -74,13 +81,15 @@ private:
1038 void unsetHalted() { flags_ &= ~flag_halted; }
1039 void set(bool ime, bool halted) { flags_ = halted * flag_halted + ime * flag_ime; }
1041 + void loadOrSave(loadsave& state) { state(flags_); }
1043 private:
1044 unsigned char flags_;
1045 enum { flag_ime = 1, flag_halted = 2 };
1048 MinKeeper<intevent_last + 1> eventTimes_;
1049 - unsigned long minIntTime_;
1050 + unsigned minIntTime_;
1051 unsigned ifreg_;
1052 unsigned iereg_;
1053 IntFlags intFlags_;
1054 diff --git a/libgambatte/src/loadsave.cpp b/libgambatte/src/loadsave.cpp
1055 new file mode 100644
1056 index 0000000..37ea71a
1057 --- /dev/null
1058 +++ b/libgambatte/src/loadsave.cpp
1059 @@ -0,0 +1,266 @@
1060 +/***************************************************************************
1061 + * Copyright (C) 2012 by H. Ilari Liusvaara *
1062 + * ilari.liusvaara@elisanet.fi *
1063 + * *
1064 + * This program is free software; you can redistribute it and/or modify *
1065 + * it under the terms of the GNU General Public License version 2 as *
1066 + * published by the Free Software Foundation. *
1067 + * *
1068 + * This program is distributed in the hope that it will be useful, *
1069 + * but WITHOUT ANY WARRANTY; without even the implied warranty of *
1070 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
1071 + * GNU General Public License version 2 for more details. *
1072 + * *
1073 + * You should have received a copy of the GNU General Public License *
1074 + * version 2 along with this program; if not, write to the *
1075 + * Free Software Foundation, Inc., *
1076 + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
1077 + ***************************************************************************/
1078 +#include "loadsave.h"
1079 +#include <stdexcept>
1080 +#include <cstring>
1081 +#include <iostream>
1083 +namespace gambatte {
1085 +loadsave::~loadsave() throw() {}
1087 +loadsave_load::loadsave_load(const std::vector<char>& _memory)
1088 + : memory(_memory)
1090 + ptr = 0;
1093 +template<typename T> void loadsave_load::do_op(T& x)
1095 + unsigned long long v = 0;
1096 + if(ptr + sizeof(T) > memory.size())
1097 + throw std::runtime_error("Loadstate overflow");
1098 + for(size_t i = 0; i < sizeof(T); i++)
1099 + v |= ((unsigned long long)(unsigned char)memory[ptr++] << (8 * (sizeof(T) - i - 1)));
1100 + x = (T)v;
1103 +template<typename T> void loadsave_load::do_op(T& x, unsigned char _tag)
1105 + if(ptr + 1 > memory.size())
1106 + throw std::runtime_error("Loadstate overflow");
1107 + unsigned char _rtag = memory[ptr++];
1108 + if(_rtag != _tag) {
1109 + std::cerr << "Wrong type tag: expected=" << (int)_tag << ", got=" << (int)_rtag << std::endl;
1110 + throw std::runtime_error("Loadstate desynced");
1112 + do_op(x);
1115 +template<typename T> void loadsave_load::do_op(T* x, size_t s, unsigned char _tag)
1117 + if(ptr + 1 > memory.size())
1118 + throw std::runtime_error("Loadstate overflow");
1119 + unsigned char _rtag = memory[ptr++];
1120 + if(_rtag != _tag) {
1121 + std::cerr << "Wrong type tag: expected=" << (int)_tag << ", got=" << (int)_rtag << std::endl;
1122 + throw std::runtime_error("Loadstate desynced");
1124 + unsigned size;
1125 + do_op(size);
1126 + if(size != s) {
1127 + std::cerr << "Wrong number of entries: expected=" << s << ", got=" << size << std::endl;
1128 + throw std::runtime_error("Loadstate desynced");
1130 + for(size_t i = 0; i < s; i++)
1131 + do_op(x[i]);
1134 +void loadsave_load::operator()(bool& x)
1136 + char c;
1137 + do_op(c, 0);
1138 + x = (c != 0);
1142 +loadsave_load::~loadsave_load() throw() {}
1143 +void loadsave_load::operator()(signed char& x) { do_op(x, 1); }
1144 +void loadsave_load::operator()(unsigned char& x) { do_op(x, 2); }
1145 +void loadsave_load::operator()(signed short& x) { do_op(x, 3); }
1146 +void loadsave_load::operator()(unsigned short& x) { do_op(x, 4); }
1147 +void loadsave_load::operator()(signed int& x) { do_op(x, 5); }
1148 +void loadsave_load::operator()(unsigned int& x) { do_op(x, 6); }
1149 +void loadsave_load::operator()(signed long long& x) { do_op(x, 7); }
1150 +void loadsave_load::operator()(unsigned long long& x) { do_op(x, 8); }
1151 +void loadsave_load::operator()(signed char* x, size_t s) { do_op(x, s, 9); }
1152 +void loadsave_load::operator()(unsigned char* x, size_t s) { do_op(x, s, 10); }
1153 +void loadsave_load::operator()(signed short* x, size_t s) { do_op(x, s, 11); }
1154 +void loadsave_load::operator()(unsigned short* x, size_t s) { do_op(x, s, 12); }
1155 +void loadsave_load::operator()(signed int* x, size_t s) { do_op(x, s, 13); }
1156 +void loadsave_load::operator()(unsigned int* x, size_t s) { do_op(x, s, 14); }
1157 +void loadsave_load::operator()(signed long long* x, size_t s) { do_op(x, s, 15); }
1158 +void loadsave_load::operator()(unsigned long long* x, size_t s) { do_op(x, s, 16); }
1160 +void loadsave_load::tag(unsigned short _tag)
1162 + unsigned short _rtag;
1163 + do_op(_rtag, 18);
1164 + if(_tag != _rtag) {
1165 + std::cerr << "Wrong inner tag: expected=" << (int)_tag << ", got=" << (int)_rtag << std::endl;
1166 + throw std::runtime_error("Loadstate desynced");
1170 +void loadsave_load::operator()(unsigned char*& ptr, unsigned char* abase)
1172 + char x;
1173 + do_op(x, 17);
1174 + if(!x)
1175 + ptr = NULL;
1176 + else {
1177 + unsigned y;
1178 + do_op(y);
1179 + ptr = abase + y;
1183 +void loadsave_load::operator()(const unsigned char*& ptr, unsigned char* abase)
1185 + char x;
1186 + do_op(x, 19);
1187 + if(!x)
1188 + ptr = NULL;
1189 + else {
1190 + unsigned y;
1191 + do_op(y);
1192 + ptr = abase + y;
1197 +bool loadsave_load::saving() { return false; }
1199 +#define BLOCKBYTES 65500
1201 +void loadsave_save::pushbytes(char* bytes, size_t amount)
1203 + if(!nextptr || memory[nextptr - 1].second + amount > BLOCKBYTES) {
1204 + memory.push_back(std::make_pair(new char[BLOCKBYTES], (size_t)0));
1205 + nextptr++;
1207 + if(cmp.size())
1208 + try { if(cmp.size() < used + amount || memcmp(&cmp[used], bytes, amount)) throw 42; } catch(...) {}
1209 + memcpy(memory[nextptr - 1].first + memory[nextptr - 1].second, bytes, amount);
1210 + memory[nextptr - 1].second += amount;
1211 + used += amount;
1214 +template<typename T> void loadsave_save::do_op(T& x)
1216 + unsigned long long v = x;
1217 + char buf[sizeof(T)];
1218 + for(size_t i = 0; i < sizeof(T); i++)
1219 + buf[i] = v >> (8 * (sizeof(T) - i - 1));
1220 + pushbytes(buf, sizeof(T));
1223 +template<typename T> void loadsave_save::do_op(T& x, unsigned char _tag)
1225 + pushbytes((char*)&_tag, 1);
1226 + do_op(x);
1229 +template<typename T> void loadsave_save::do_op(T* x, size_t s, unsigned char _tag)
1231 + pushbytes((char*)&_tag, 1);
1232 + unsigned size = s;
1233 + do_op(size);
1234 + for(size_t i = 0; i < s; i++)
1235 + do_op(x[i]);
1238 +loadsave_save::loadsave_save()
1240 + used = 0;
1241 + nextptr = 0;
1244 +loadsave_save::loadsave_save(const std::vector<char>& _memory)
1246 + used = 0;
1247 + nextptr = 0;
1248 + cmp = _memory;
1251 +loadsave_save::~loadsave_save() throw()
1253 + for(auto i : memory)
1254 + delete[] i.first;
1257 +void loadsave_save::operator()(bool& x)
1259 + char y = x ? 1 : 0;
1260 + char z = 0;
1261 + pushbytes(&z, 1);
1262 + pushbytes(&y, 1);
1265 +void loadsave_save::operator()(signed char& x) { do_op(x, 1); }
1266 +void loadsave_save::operator()(unsigned char& x) { do_op(x, 2); }
1267 +void loadsave_save::operator()(signed short& x) { do_op(x, 3); }
1268 +void loadsave_save::operator()(unsigned short& x) { do_op(x, 4); }
1269 +void loadsave_save::operator()(signed int& x) { do_op(x, 5); }
1270 +void loadsave_save::operator()(unsigned int& x) { do_op(x, 6); }
1271 +void loadsave_save::operator()(signed long long& x) { do_op(x, 7); }
1272 +void loadsave_save::operator()(unsigned long long& x) { do_op(x, 8); }
1273 +void loadsave_save::operator()(signed char* x, size_t s) { do_op(x, s, 9); }
1274 +void loadsave_save::operator()(unsigned char* x, size_t s) { do_op(x, s, 10); }
1275 +void loadsave_save::operator()(signed short* x, size_t s) { do_op(x, s, 11); }
1276 +void loadsave_save::operator()(unsigned short* x, size_t s) { do_op(x, s, 12); }
1277 +void loadsave_save::operator()(signed int* x, size_t s) { do_op(x, s, 13); }
1278 +void loadsave_save::operator()(unsigned int* x, size_t s) { do_op(x, s, 14); }
1279 +void loadsave_save::operator()(signed long long* x, size_t s) { do_op(x, s, 15); }
1280 +void loadsave_save::operator()(unsigned long long* x, size_t s) { do_op(x, s, 16); }
1281 +bool loadsave_save::saving() { return true; }
1283 +void loadsave_save::operator()(unsigned char*& ptr, unsigned char* abase)
1285 + if(!ptr) {
1286 + char x = 0;
1287 + do_op(x, 17);
1288 + } else {
1289 + char x = 1;
1290 + unsigned y = ptr - abase;
1291 + do_op(x, 17);
1292 + do_op(y);
1296 +void loadsave_save::operator()(const unsigned char*& ptr, unsigned char* abase)
1298 + if(!ptr) {
1299 + char x = 0;
1300 + do_op(x, 19);
1301 + } else {
1302 + char x = 1;
1303 + unsigned y = ptr - abase;
1304 + do_op(x, 19);
1305 + do_op(y);
1309 +void loadsave_save::tag(unsigned short _tag)
1311 + do_op(_tag, 18);
1314 +std::vector<char> loadsave_save::get()
1316 + std::vector<char> x;
1317 + x.resize(used);
1318 + size_t ptr = 0;
1319 + for(auto i : memory) {
1320 + memcpy(&x[ptr], i.first, i.second);
1321 + ptr += i.second;
1323 + return x;
1326 diff --git a/libgambatte/src/loadsave.h b/libgambatte/src/loadsave.h
1327 new file mode 100644
1328 index 0000000..10ebf63
1329 --- /dev/null
1330 +++ b/libgambatte/src/loadsave.h
1331 @@ -0,0 +1,160 @@
1332 +#ifndef _loadsave__hpp__included__
1333 +#define _loadsave__hpp__included__
1334 +/***************************************************************************
1335 + * Copyright (C) 2012 by H. Ilari Liusvaara *
1336 + * ilari.liusvaara@elisanet.fi *
1337 + * *
1338 + * This program is free software; you can redistribute it and/or modify *
1339 + * it under the terms of the GNU General Public License version 2 as *
1340 + * published by the Free Software Foundation. *
1341 + * *
1342 + * This program is distributed in the hope that it will be useful, *
1343 + * but WITHOUT ANY WARRANTY; without even the implied warranty of *
1344 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
1345 + * GNU General Public License version 2 for more details. *
1346 + * *
1347 + * You should have received a copy of the GNU General Public License *
1348 + * version 2 along with this program; if not, write to the *
1349 + * Free Software Foundation, Inc., *
1350 + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
1351 + ***************************************************************************/
1353 +#include <cstdint>
1354 +#include <vector>
1355 +#include <cstdlib>
1356 +#include <stdexcept>
1358 +namespace gambatte {
1359 + class loadsave
1361 + private:
1362 + unsigned enumVal;
1363 + bool enumAssigned;
1364 + public:
1365 + virtual ~loadsave() throw();
1366 + virtual void operator()(bool& x) = 0;
1367 + virtual void operator()(signed char& x) = 0;
1368 + virtual void operator()(unsigned char& x) = 0;
1369 + virtual void operator()(signed short& x) = 0;
1370 + virtual void operator()(unsigned short& x) = 0;
1371 + virtual void operator()(signed int& x) = 0;
1372 + virtual void operator()(unsigned int& x) = 0;
1373 + virtual void operator()(signed long long& x) = 0;
1374 + virtual void operator()(unsigned long long& x) = 0;
1375 + virtual void operator()(signed char* x, size_t s) = 0;
1376 + virtual void operator()(unsigned char* x, size_t s) = 0;
1377 + virtual void operator()(signed short* x, size_t s) = 0;
1378 + virtual void operator()(unsigned short* x, size_t s) = 0;
1379 + virtual void operator()(signed int* x, size_t s) = 0;
1380 + virtual void operator()(unsigned int* x, size_t s) = 0;
1381 + virtual void operator()(long long* x, size_t s) = 0;
1382 + virtual void operator()(unsigned long long* x, size_t s) = 0;
1383 + virtual void operator()(unsigned char*& ptr, unsigned char* abase) = 0;
1384 + virtual void operator()(const unsigned char*& ptr, unsigned char* abase) = 0;
1385 + virtual void tag(unsigned short tag) = 0;
1386 + void time(time_t& t) {
1387 + unsigned long long t_ = t;
1388 + (*this)(t_);
1389 + t = t_;
1391 + void startEnumeration() {
1392 + enumAssigned = false;
1393 + enumVal = 0xFFFFFFFFU;
1394 + if(!saving())
1395 + (*this)(enumVal);
1397 + template<typename T> void enumerate(T& ptr, T candiate, unsigned symbol) {
1398 + if(saving()) {
1399 + if(ptr == candiate) {
1400 + enumVal = symbol;
1401 + enumAssigned = true;
1403 + } else {
1404 + if(enumVal == symbol) {
1405 + ptr = candiate;
1406 + enumAssigned = true;
1410 + void endEnumeration() {
1411 + if(saving())
1412 + (*this)(enumVal);
1413 + if(!enumAssigned)
1414 + throw std::runtime_error("Enumeration missing a choice");
1416 + virtual bool saving() = 0;
1417 + };
1419 + class loadsave_load : public loadsave
1421 + const std::vector<char>& memory;
1422 + size_t ptr;
1423 + template<typename T> inline void do_op(T& x);
1424 + template<typename T> inline void do_op(T& x, unsigned char _tag);
1425 + template<typename T> void do_op(T* x, size_t s, unsigned char _tag);
1426 + public:
1427 + loadsave_load(const std::vector<char>& _memory);
1428 + ~loadsave_load() throw();
1429 + void operator()(bool& x);
1430 + void operator()(signed char& x);
1431 + void operator()(unsigned char& x);
1432 + void operator()(signed short& x);
1433 + void operator()(unsigned short& x);
1434 + void operator()(signed int& x);
1435 + void operator()(unsigned int& x);
1436 + void operator()(signed long long& x);
1437 + void operator()(unsigned long long& x);
1438 + void operator()(signed char* x, size_t s);
1439 + void operator()(unsigned char* x, size_t s);
1440 + void operator()(signed short* x, size_t s);
1441 + void operator()(unsigned short* x, size_t s);
1442 + void operator()(signed int* x, size_t s);
1443 + void operator()(unsigned int* x, size_t s);
1444 + void operator()(signed long long* x, size_t s);
1445 + void operator()(unsigned long long* x, size_t s);
1446 + void operator()(unsigned char*& ptr, unsigned char* abase);
1447 + void operator()(const unsigned char*& ptr, unsigned char* abase);
1448 + void tag(unsigned short _tag);
1449 + bool saving();
1450 + };
1452 + class loadsave_save : public loadsave
1454 + std::vector<std::pair<char*, size_t>> memory;
1455 + size_t nextptr;
1456 + size_t used;
1457 + inline void pushbytes(char* bytes, size_t amount);
1458 + template<typename T> inline void do_op(T& x);
1459 + template<typename T> inline void do_op(T& x, unsigned char _tag);
1460 + template<typename T> void do_op(T* x, size_t s, unsigned char _tag);
1461 + std::vector<char> cmp;
1462 + public:
1463 + loadsave_save();
1464 + loadsave_save(const std::vector<char>& _memory);
1465 + ~loadsave_save() throw();
1466 + void operator()(bool& x);
1467 + void operator()(signed char& x);
1468 + void operator()(unsigned char& x);
1469 + void operator()(signed short& x);
1470 + void operator()(unsigned short& x);
1471 + void operator()(signed int& x);
1472 + void operator()(unsigned int& x);
1473 + void operator()(signed long long& x);
1474 + void operator()(unsigned long long& x);
1475 + void operator()(signed char* x, size_t s);
1476 + void operator()(unsigned char* x, size_t s);
1477 + void operator()(signed short* x, size_t s);
1478 + void operator()(unsigned short* x, size_t s);
1479 + void operator()(signed int* x, size_t s);
1480 + void operator()(unsigned int* x, size_t s);
1481 + void operator()(signed long long* x, size_t s);
1482 + void operator()(unsigned long long* x, size_t s);
1483 + void operator()(unsigned char*& ptr, unsigned char* abase);
1484 + void operator()(const unsigned char*& ptr, unsigned char* abase);
1485 + void tag(unsigned short _tag);
1486 + bool saving();
1487 + std::vector<char> get();
1488 + };
1491 +#endif
1492 diff --git a/libgambatte/src/mem/cartridge.cpp b/libgambatte/src/mem/cartridge.cpp
1493 index 75629f6..d593dc5 100644
1494 --- a/libgambatte/src/mem/cartridge.cpp
1495 +++ b/libgambatte/src/mem/cartridge.cpp
1496 @@ -23,6 +23,10 @@
1497 #include <cstring>
1498 #include <fstream>
1501 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
1502 +// - Make it rerecording-friendly.
1504 namespace gambatte {
1506 namespace {
1507 @@ -36,6 +40,8 @@ public:
1508 virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const {
1509 return (addr< 0x4000) == (bank == 0);
1511 + void loadOrSave(loadsave& state) {
1515 class Mbc0 : public DefaultMbc {
1516 @@ -61,6 +67,9 @@ public:
1517 enableRam_ = ss.enableRam;
1518 memptrs_.setRambank(enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : 0, 0);
1520 + void loadOrSave(loadsave& state) {
1521 + state(enableRam_);
1524 private:
1525 MemPtrs &memptrs_;
1526 @@ -130,6 +139,12 @@ public:
1527 setRombank();
1530 + void loadOrSave(loadsave& state) {
1531 + state(rombank_);
1532 + state(rambank_);
1533 + state(enableRam_);
1534 + state(rambankMode_);
1536 private:
1537 MemPtrs &memptrs_;
1538 unsigned char rombank_;
1539 @@ -197,6 +212,11 @@ public:
1540 virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const {
1541 return (addr < 0x4000) == ((bank & 0xF) == 0);
1543 + void loadOrSave(loadsave& state) {
1544 + state(rombank_);
1545 + state(enableRam_);
1546 + state(rombank0Mode_);
1549 private:
1550 MemPtrs &memptrs_;
1551 @@ -251,6 +271,10 @@ public:
1552 memptrs_.setRambank(enableRam_ ? MemPtrs::read_en | MemPtrs::write_en : 0, 0);
1553 memptrs_.setRombank(rombank_ & (rombanks(memptrs_) - 1));
1555 + void loadOrSave(loadsave& state) {
1556 + state(rombank_);
1557 + state(enableRam_);
1560 private:
1561 MemPtrs &memptrs_;
1562 @@ -304,7 +328,12 @@ public:
1563 setRambank();
1564 memptrs_.setRombank(rombank_ & (rombanks(memptrs_) - 1));
1567 + void loadOrSave(loadsave& state) {
1568 + rtc_->loadOrSave(state);
1569 + state(rombank_);
1570 + state(rambank_);
1571 + state(enableRam_);
1573 private:
1574 MemPtrs &memptrs_;
1575 Rtc *const rtc_;
1576 @@ -374,7 +403,12 @@ public:
1577 setRambank();
1578 setRombank();
1581 + void loadOrSave(loadsave& state) {
1582 + state(rombank_);
1583 + state(rambank_);
1584 + state(enableRam_);
1585 + state(rambankMode_);
1587 private:
1588 MemPtrs &memptrs_;
1589 unsigned char rombank_;
1590 @@ -437,6 +471,11 @@ public:
1591 setRambank();
1592 setRombank();
1594 + void loadOrSave(loadsave& state) {
1595 + state(rombank_);
1596 + state(rambank_);
1597 + state(enableRam_);
1600 private:
1601 MemPtrs &memptrs_;
1602 @@ -536,6 +575,15 @@ LoadRes Cartridge::loadROM(std::string const &romfile,
1603 bool const multicartCompat)
1605 scoped_ptr<File> const rom(newFileInstance(romfile));
1606 + return loadROM(rom.get(), forceDmg, multicartCompat, romfile);
1609 +LoadRes Cartridge::loadROM(const unsigned char* image, size_t isize, const bool forceDmg, const bool multicartCompat) {
1610 + const scoped_ptr<File> rom(newFileInstance(image, isize));
1611 + return loadROM(rom.get(), forceDmg, multicartCompat, "");
1614 +LoadRes Cartridge::loadROM(File* rom, const bool forceDmg, const bool multicartCompat, const std::string& filename) {
1615 if (rom->fail())
1616 return LOADRES_IO_ERROR;
1618 @@ -626,7 +674,14 @@ LoadRes Cartridge::loadROM(std::string const &romfile,
1619 if (rom->fail())
1620 return LOADRES_IO_ERROR;
1622 - defaultSaveBasePath_ = stripExtension(romfile);
1623 + if(filename != "") {
1624 + defaultSaveBasePath_ = stripExtension(filename);
1625 + memoryCartridge = false;
1626 + } else {
1627 + defaultSaveBasePath_ = "";
1628 + memoryCartridge = true;
1630 + clearMemorySavedData();
1632 switch (type) {
1633 case type_plain: mbc_.reset(new Mbc0(memptrs_)); break;
1634 @@ -667,43 +722,67 @@ void Cartridge::loadSavedata() {
1635 std::string const &sbp = saveBasePath();
1637 if (hasBattery(memptrs_.romdata()[0x147])) {
1638 - std::ifstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::in);
1639 + if(memoryCartridge) {
1640 + if(memoryCartridgeSram.size())
1641 + memcpy(memptrs_.rambankdata(), &memoryCartridgeSram[0], memptrs_.rambankdataend() - memptrs_.rambankdata());
1642 + } else {
1643 + std::ifstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::in);
1645 - if (file.is_open()) {
1646 - file.read(reinterpret_cast<char*>(memptrs_.rambankdata()),
1647 - memptrs_.rambankdataend() - memptrs_.rambankdata());
1648 - enforce8bit(memptrs_.rambankdata(), memptrs_.rambankdataend() - memptrs_.rambankdata());
1649 + if (file.is_open()) {
1650 + file.read(reinterpret_cast<char*>(memptrs_.rambankdata()),
1651 + memptrs_.rambankdataend() - memptrs_.rambankdata());
1652 + enforce8bit(memptrs_.rambankdata(), memptrs_.rambankdataend() - memptrs_.rambankdata());
1657 if (hasRtc(memptrs_.romdata()[0x147])) {
1658 - std::ifstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::in);
1659 - if (file) {
1660 - unsigned long basetime = file.get() & 0xFF;
1661 - basetime = basetime << 8 | (file.get() & 0xFF);
1662 - basetime = basetime << 8 | (file.get() & 0xFF);
1663 - basetime = basetime << 8 | (file.get() & 0xFF);
1664 - rtc_.setBaseTime(basetime);
1665 + if(memoryCartridge) {
1666 + rtc_.setBaseTime(memoryCartridgeRtcBase);
1667 + } else {
1668 + std::ifstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::in);
1669 + if (file) {
1670 + unsigned basetime = file.get() & 0xFF;
1671 + basetime = basetime << 8 | (file.get() & 0xFF);
1672 + basetime = basetime << 8 | (file.get() & 0xFF);
1673 + basetime = basetime << 8 | (file.get() & 0xFF);
1674 + rtc_.setBaseTime(basetime);
1680 +void Cartridge::clearMemorySavedData()
1682 + memoryCartridgeRtcBase = 0;
1683 + memoryCartridgeSram.resize(0);
1686 void Cartridge::saveSavedata() {
1687 std::string const &sbp = saveBasePath();
1689 if (hasBattery(memptrs_.romdata()[0x147])) {
1690 - std::ofstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::out);
1691 - file.write(reinterpret_cast<char const *>(memptrs_.rambankdata()),
1692 - memptrs_.rambankdataend() - memptrs_.rambankdata());
1693 + if(memoryCartridge) {
1694 + memoryCartridgeSram.resize(memptrs_.rambankdataend() - memptrs_.rambankdata());
1695 + memcpy(&memoryCartridgeSram[0], memptrs_.rambankdata(), memptrs_.rambankdataend() - memptrs_.rambankdata());
1696 + } else {
1697 + std::ofstream file((sbp + ".sav").c_str(), std::ios::binary | std::ios::out);
1698 + file.write(reinterpret_cast<const char*>(memptrs_.rambankdata()),
1699 + memptrs_.rambankdataend() - memptrs_.rambankdata());
1703 if (hasRtc(memptrs_.romdata()[0x147])) {
1704 - std::ofstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::out);
1705 - unsigned long const basetime = rtc_.baseTime();
1706 - file.put(basetime >> 24 & 0xFF);
1707 - file.put(basetime >> 16 & 0xFF);
1708 - file.put(basetime >> 8 & 0xFF);
1709 - file.put(basetime & 0xFF);
1710 + if(memoryCartridge) {
1711 + memoryCartridgeRtcBase = rtc_.getBaseTime();
1712 + } else {
1713 + std::ofstream file((sbp + ".rtc").c_str(), std::ios::binary | std::ios::out);
1714 + const unsigned basetime = rtc_.getBaseTime();
1715 + file.put(basetime >> 24 & 0xFF);
1716 + file.put(basetime >> 16 & 0xFF);
1717 + file.put(basetime >> 8 & 0xFF);
1718 + file.put(basetime & 0xFF);
1723 @@ -764,4 +843,36 @@ PakInfo const Cartridge::pakInfo(bool const multipakCompat) const {
1724 return PakInfo();
1727 +std::pair<unsigned char*, size_t> Cartridge::getSaveRam() {
1728 + size_t sramsize = memptrs_.rambankdataend() - memptrs_.rambankdata();
1729 + return std::make_pair(memptrs_.rambankdata(), sramsize);
1732 +std::pair<unsigned char*, size_t> Cartridge::getVideoRam() {
1733 + size_t vramsize = memptrs_.vramdataend() - memptrs_.vramdata();
1734 + return std::make_pair(memptrs_.vramdata(), vramsize);
1737 +std::pair<unsigned char*, size_t> Cartridge::getWorkRam() {
1738 + size_t worksize = memptrs_.wramdataend() - memptrs_.wramdata(0);
1739 + return std::make_pair(memptrs_.wramdata(0), worksize);
1742 +Cartridge::Cartridge(time_t (**_getCurrentTime)())
1743 + : rtc_(_getCurrentTime) {
1744 + memoryCartridge = true;
1747 +void Cartridge::loadOrSave(loadsave& state) {
1748 + memptrs_.loadOrSave(state);
1749 + rtc_.loadOrSave(state);
1750 + mbc_->loadOrSave(state);
1751 + unsigned ggsize = ggUndoList_.size();
1752 + state(ggsize);
1753 + if(!state.saving())
1754 + ggUndoList_.resize(ggsize);
1755 + for(size_t i = 0; i < ggsize; i++)
1756 + ggUndoList_[i].loadOrSave(state);
1760 diff --git a/libgambatte/src/mem/cartridge.h b/libgambatte/src/mem/cartridge.h
1761 index 4c2d7b4..dd342b6 100644
1762 --- a/libgambatte/src/mem/cartridge.h
1763 +++ b/libgambatte/src/mem/cartridge.h
1764 @@ -26,9 +26,16 @@
1765 #include "scoped_ptr.h"
1766 #include <string>
1767 #include <vector>
1768 +#include "../loadsave.h"
1771 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
1772 +// - Make it rerecording-friendly.
1774 namespace gambatte {
1776 +class File;
1778 class Mbc {
1779 public:
1780 virtual ~Mbc() {}
1781 @@ -36,23 +43,16 @@ public:
1782 virtual void saveState(SaveState::Mem &ss) const = 0;
1783 virtual void loadState(SaveState::Mem const &ss) = 0;
1784 virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned address, unsigned rombank) const = 0;
1785 + virtual void loadOrSave(loadsave& state) = 0;
1788 class Cartridge {
1789 public:
1790 + Cartridge(time_t (**_getCurrentTime)());
1791 void setStatePtrs(SaveState &);
1792 void saveState(SaveState &) const;
1793 void loadState(SaveState const &);
1794 bool loaded() const { return mbc_.get(); }
1795 - unsigned char const * rmem(unsigned area) const { return memptrs_.rmem(area); }
1796 - unsigned char * wmem(unsigned area) const { return memptrs_.wmem(area); }
1797 - unsigned char * vramdata() const { return memptrs_.vramdata(); }
1798 - unsigned char * romdata(unsigned area) const { return memptrs_.romdata(area); }
1799 - unsigned char * wramdata(unsigned area) const { return memptrs_.wramdata(area); }
1800 - unsigned char const * rdisabledRam() const { return memptrs_.rdisabledRam(); }
1801 - unsigned char const * rsrambankptr() const { return memptrs_.rsrambankptr(); }
1802 - unsigned char * wsrambankptr() const { return memptrs_.wsrambankptr(); }
1803 - unsigned char * vrambankptr() const { return memptrs_.vrambankptr(); }
1804 OamDmaSrc oamDmaSrc() const { return memptrs_.oamDmaSrc(); }
1805 void setVrambank(unsigned bank) { memptrs_.setVrambank(bank); }
1806 void setWrambank(unsigned bank) { memptrs_.setWrambank(bank); }
1807 @@ -65,16 +65,40 @@ public:
1808 void saveSavedata();
1809 std::string const saveBasePath() const;
1810 void setSaveDir(std::string const &dir);
1811 - LoadRes loadROM(std::string const &romfile, bool forceDmg, bool multicartCompat);
1812 char const * romTitle() const { return reinterpret_cast<char const *>(memptrs_.romdata() + 0x134); }
1813 class PakInfo const pakInfo(bool multicartCompat) const;
1814 void setGameGenie(std::string const &codes);
1815 + const unsigned char * rmem(unsigned area) const { return memptrs_.rmem(area); }
1816 + unsigned char * wmem(unsigned area) const { return memptrs_.wmem(area); }
1817 + unsigned char * vramdata() const { return memptrs_.vramdata(); }
1818 + unsigned char * romdata(unsigned area) const { return memptrs_.romdata(area); }
1819 + unsigned char * wramdata(unsigned area) const { return memptrs_.wramdata(area); }
1820 + const unsigned char * rdisabledRam() const { return memptrs_.rdisabledRam(); }
1821 + const unsigned char * rsrambankptr() const { return memptrs_.rsrambankptr(); }
1822 + unsigned char * wsrambankptr() const { return memptrs_.wsrambankptr(); }
1823 + unsigned char * vrambankptr() const { return memptrs_.vrambankptr(); }
1825 + void loadOrSave(loadsave& state);
1826 + void setRtcBase(time_t time) { rtc_.setBaseTime(time); }
1827 + time_t getRtcBase() { return rtc_.getBaseTime(); }
1828 + std::pair<unsigned char*, size_t> getWorkRam();
1829 + std::pair<unsigned char*, size_t> getSaveRam();
1830 + std::pair<unsigned char*, size_t> getVideoRam();
1831 + LoadRes loadROM(const std::string &romfile, bool forceDmg, bool multicartCompat);
1832 + LoadRes loadROM(const unsigned char* image, size_t isize, bool forceDmg, bool multicartCompat);
1833 + LoadRes loadROM(File* rom, const bool forceDmg, const bool multicartCompat, const std::string& filename);
1834 + void clearMemorySavedData();
1836 private:
1837 struct AddrData {
1838 - unsigned long addr;
1839 + unsigned addr;
1840 unsigned char data;
1841 - AddrData(unsigned long addr, unsigned data) : addr(addr), data(data) {}
1842 + AddrData(unsigned addr, unsigned data) : addr(addr), data(data) {}
1843 + AddrData() {}
1844 + void loadOrSave(loadsave& state) {
1845 + state(addr);
1846 + state(data);
1850 MemPtrs memptrs_;
1851 @@ -83,6 +107,9 @@ private:
1852 std::string defaultSaveBasePath_;
1853 std::string saveDir_;
1854 std::vector<AddrData> ggUndoList_;
1855 + bool memoryCartridge;
1856 + time_t memoryCartridgeRtcBase;
1857 + std::vector<unsigned char> memoryCartridgeSram;
1859 void applyGameGenie(std::string const &code);
1861 diff --git a/libgambatte/src/mem/memptrs.cpp b/libgambatte/src/mem/memptrs.cpp
1862 index e29b855..f351d94 100644
1863 --- a/libgambatte/src/mem/memptrs.cpp
1864 +++ b/libgambatte/src/mem/memptrs.cpp
1865 @@ -20,6 +20,10 @@
1866 #include <algorithm>
1867 #include <cstring>
1870 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
1871 +// - Make it rerecording-friendly.
1873 namespace gambatte {
1875 MemPtrs::MemPtrs()
1876 @@ -43,13 +47,11 @@ MemPtrs::~MemPtrs() {
1878 void MemPtrs::reset(unsigned const rombanks, unsigned const rambanks, unsigned const wrambanks) {
1879 delete []memchunk_;
1880 - memchunk_ = new unsigned char[
1881 - 0x4000
1882 - + rombanks * 0x4000ul
1883 - + 0x4000
1884 - + rambanks * 0x2000ul
1885 - + wrambanks * 0x1000ul
1886 - + 0x4000];
1887 + memchunk_size = 0x4000 + rombanks * 0x4000ul + 0x4000 + rambanks * 0x2000ul + wrambanks * 0x1000ul + 0x4000;
1888 + memchunk_ = new unsigned char[memchunk_size];
1890 + //FIXME: Make this random.
1891 + memset(memchunk_, 0, memchunk_size);
1893 romdata_[0] = romdata();
1894 rambankdata_ = romdata_[0] + rombanks * 0x4000ul + 0x4000;
1895 @@ -155,4 +157,26 @@ void MemPtrs::disconnectOamDmaAreas() {
1899 +void MemPtrs::loadOrSave(loadsave& state)
1901 + state(memchunk_, 0x4000);
1902 + state(romdataend(), memchunk_size - (romdataend() - memchunk_));
1903 + int oamDmaSrc_2 = oamDmaSrc_;
1904 + state(oamDmaSrc_2);
1905 + oamDmaSrc_ = (OamDmaSrc)oamDmaSrc_2;
1906 + //Rmem is constant.
1907 + for(unsigned i = 0; i < 0x10; i++)
1908 + state(wmem_[i], memchunk_);
1909 + for(unsigned i = 0; i < 0x10; i++)
1910 + state(rmem_[i], memchunk_);
1911 + state(romdata_[0], memchunk_);
1912 + state(romdata_[1], memchunk_);
1913 + state(rambankdata_, memchunk_);
1914 + state(rsrambankptr_, memchunk_);
1915 + state(wsrambankptr_, memchunk_);
1916 + state(wramdataend_, memchunk_);
1917 + state(vrambankptr_, memchunk_);
1918 + //memchunk_size is cart constant, not saved.
1922 diff --git a/libgambatte/src/mem/memptrs.h b/libgambatte/src/mem/memptrs.h
1923 index bd0e176..6553955 100644
1924 --- a/libgambatte/src/mem/memptrs.h
1925 +++ b/libgambatte/src/mem/memptrs.h
1926 @@ -19,6 +19,12 @@
1927 #ifndef MEMPTRS_H
1928 #define MEMPTRS_H
1930 +#include "../loadsave.h"
1933 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
1934 +// - Make it rerecording-friendly.
1936 namespace gambatte {
1938 enum OamDmaSrc { oam_dma_src_rom,
1939 @@ -60,6 +66,7 @@ public:
1940 void setWrambank(unsigned bank);
1941 void setOamDmaSrc(OamDmaSrc oamDmaSrc);
1943 + void loadOrSave(loadsave& state);
1944 private:
1945 unsigned char const *rmem_[0x10];
1946 unsigned char *wmem_[0x10];
1947 @@ -72,6 +79,7 @@ private:
1948 unsigned char *rambankdata_;
1949 unsigned char *wramdataend_;
1950 OamDmaSrc oamDmaSrc_;
1951 + size_t memchunk_size;
1953 MemPtrs(MemPtrs const &);
1954 MemPtrs & operator=(MemPtrs const &);
1955 diff --git a/libgambatte/src/mem/rtc.cpp b/libgambatte/src/mem/rtc.cpp
1956 index 1a46867..4a98bbe 100644
1957 --- a/libgambatte/src/mem/rtc.cpp
1958 +++ b/libgambatte/src/mem/rtc.cpp
1959 @@ -19,9 +19,13 @@
1960 #include "rtc.h"
1961 #include "../savestate.h"
1964 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
1965 +// - Make it rerecording-friendly.
1967 namespace gambatte {
1969 -Rtc::Rtc()
1970 +Rtc::Rtc(time_t (**_getCurrentTime)())
1971 : activeData_(0)
1972 , activeSet_(0)
1973 , baseTime_(0)
1974 @@ -34,11 +38,12 @@ Rtc::Rtc()
1975 , dataS_(0)
1976 , enabled_(false)
1977 , lastLatchData_(false)
1978 +, getCurrentTime(_getCurrentTime)
1982 void Rtc::doLatch() {
1983 - std::time_t tmp = (dataDh_ & 0x40 ? haltTime_ : std::time(0)) - baseTime_;
1984 + std::time_t tmp = (dataDh_ & 0x40 ? haltTime_ : (*getCurrentTime)()) - baseTime_;
1986 while (tmp > 0x1FF * 86400) {
1987 baseTime_ += 0x1FF * 86400;
1988 @@ -112,44 +117,77 @@ void Rtc::loadState(SaveState const &state) {
1991 void Rtc::setDh(unsigned const newDh) {
1992 - std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : std::time(0);
1993 + std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : (*getCurrentTime)();
1994 std::time_t const oldHighdays = ((unixtime - baseTime_) / 86400) & 0x100;
1995 baseTime_ += oldHighdays * 86400;
1996 baseTime_ -= ((newDh & 0x1) << 8) * 86400;
1998 if ((dataDh_ ^ newDh) & 0x40) {
1999 if (newDh & 0x40)
2000 - haltTime_ = std::time(0);
2001 + haltTime_ = (*getCurrentTime)();
2002 else
2003 - baseTime_ += std::time(0) - haltTime_;
2004 + baseTime_ += (*getCurrentTime)() - haltTime_;
2009 void Rtc::setDl(unsigned const newLowdays) {
2010 - std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : std::time(0);
2011 + std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : (*getCurrentTime)();
2012 std::time_t const oldLowdays = ((unixtime - baseTime_) / 86400) & 0xFF;
2013 baseTime_ += oldLowdays * 86400;
2014 baseTime_ -= newLowdays * 86400;
2017 void Rtc::setH(unsigned const newHours) {
2018 - std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : std::time(0);
2019 + std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : (*getCurrentTime)();
2020 std::time_t const oldHours = ((unixtime - baseTime_) / 3600) % 24;
2021 baseTime_ += oldHours * 3600;
2022 baseTime_ -= newHours * 3600;
2025 void Rtc::setM(unsigned const newMinutes) {
2026 - std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : std::time(0);
2027 + std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : (*getCurrentTime)();
2028 std::time_t const oldMinutes = ((unixtime - baseTime_) / 60) % 60;
2029 baseTime_ += oldMinutes * 60;
2030 baseTime_ -= newMinutes * 60;
2033 void Rtc::setS(unsigned const newSeconds) {
2034 - std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : std::time(0);
2035 + std::time_t const unixtime = dataDh_ & 0x40 ? haltTime_ : (*getCurrentTime)();
2036 baseTime_ += (unixtime - baseTime_) % 60;
2037 baseTime_ -= newSeconds;
2040 +void Rtc::loadOrSave(loadsave& state)
2042 + state.startEnumeration();
2043 + state.enumerate<unsigned char*>(activeData_, NULL, 0);
2044 + state.enumerate(activeData_, &dataDh_, 1);
2045 + state.enumerate(activeData_, &dataDl_, 2);
2046 + state.enumerate(activeData_, &dataH_, 3);
2047 + state.enumerate(activeData_, &dataM_, 4);
2048 + state.enumerate(activeData_, &dataS_, 5);
2049 + state.endEnumeration();
2051 + state.startEnumeration();
2052 + state.enumerate<void (gambatte::Rtc::*)(unsigned int)>(activeSet_, NULL, 0);
2053 + state.enumerate(activeSet_, &Rtc::setDh, 1);
2054 + state.enumerate(activeSet_, &Rtc::setDl, 2);
2055 + state.enumerate(activeSet_, &Rtc::setH, 3);
2056 + state.enumerate(activeSet_, &Rtc::setM, 4);
2057 + state.enumerate(activeSet_, &Rtc::setS, 5);
2058 + state.endEnumeration();
2060 + state.time(baseTime_);
2061 + state.time(haltTime_);
2062 + state(index_);
2063 + state(dataDh_);
2064 + state(dataDl_);
2065 + state(dataH_);
2066 + state(dataM_);
2067 + state(dataS_);
2068 + state(enabled_);
2069 + state(lastLatchData_);
2073 diff --git a/libgambatte/src/mem/rtc.h b/libgambatte/src/mem/rtc.h
2074 index 2408067..81da102 100644
2075 --- a/libgambatte/src/mem/rtc.h
2076 +++ b/libgambatte/src/mem/rtc.h
2077 @@ -20,6 +20,12 @@
2078 #define RTC_H
2080 #include <ctime>
2081 +#include "../loadsave.h"
2084 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
2085 +// - Make it rerecording-friendly.
2088 namespace gambatte {
2090 @@ -27,7 +33,7 @@ struct SaveState;
2092 class Rtc {
2093 public:
2094 - Rtc();
2095 + Rtc(time_t (**_getCurrentTime)());
2096 unsigned char const * activeData() const { return activeData_; }
2097 std::time_t baseTime() const { return baseTime_; }
2098 void setBaseTime(std::time_t baseTime) { baseTime_ = baseTime; }
2099 @@ -56,6 +62,9 @@ public:
2100 *activeData_ = data;
2103 + std::time_t getBaseTime() const { return baseTime_; }
2105 + void loadOrSave(loadsave& state);
2106 private:
2107 unsigned char *activeData_;
2108 void (Rtc::*activeSet_)(unsigned);
2109 @@ -77,6 +86,7 @@ private:
2110 void setH(unsigned newHours);
2111 void setM(unsigned newMinutes);
2112 void setS(unsigned newSeconds);
2113 + time_t (**getCurrentTime)();
2117 diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp
2118 index 529e9f2..cc76f96 100644
2119 --- a/libgambatte/src/memory.cpp
2120 +++ b/libgambatte/src/memory.cpp
2121 @@ -23,9 +23,13 @@
2122 #include "video.h"
2123 #include <cstring>
2126 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
2127 +// - Make it rerecording-friendly.
2129 namespace gambatte {
2131 -Memory::Memory(Interrupter const &interrupter)
2132 +Memory::Memory(Interrupter const &interrupter, time_t (**_getCurrentTime)())
2133 : getInput_(0)
2134 , divLastUpdate_(0)
2135 , lastOamDmaUpdate_(disabled_time)
2136 @@ -36,6 +40,7 @@ Memory::Memory(Interrupter const &interrupter)
2137 , oamDmaPos_(0xFE)
2138 , serialCnt_(0)
2139 , blanklcd_(false)
2140 +, cart_(_getCurrentTime)
2142 intreq_.setEventTime<intevent_blit>(144 * 456ul);
2143 intreq_.setEventTime<intevent_end>(0);
2144 @@ -49,7 +54,7 @@ void Memory::setStatePtrs(SaveState &state) {
2145 psg_.setStatePtrs(state);
2148 -unsigned long Memory::saveState(SaveState &state, unsigned long cc) {
2149 +unsigned Memory::saveState(SaveState &state, unsigned cc) {
2150 cc = resetCounters(cc);
2151 nontrivial_ff_read(0x05, cc);
2152 nontrivial_ff_read(0x0F, cc);
2153 @@ -72,7 +77,7 @@ unsigned long Memory::saveState(SaveState &state, unsigned long cc) {
2154 return cc;
2157 -static int serialCntFrom(unsigned long cyclesUntilDone, bool cgbFast) {
2158 +static int serialCntFrom(unsigned cyclesUntilDone, bool cgbFast) {
2159 return cgbFast ? (cyclesUntilDone + 0xF) >> 4 : (cyclesUntilDone + 0x1FF) >> 9;
2162 @@ -118,7 +123,7 @@ void Memory::loadState(SaveState const &state) {
2163 std::memset(cart_.vramdata() + 0x2000, 0, 0x2000);
2166 -void Memory::setEndtime(unsigned long cc, unsigned long inc) {
2167 +void Memory::setEndtime(unsigned cc, unsigned inc) {
2168 if (intreq_.eventTime(intevent_blit) <= cc) {
2169 intreq_.setEventTime<intevent_blit>(intreq_.eventTime(intevent_blit)
2170 + (70224 << isDoubleSpeed()));
2171 @@ -127,7 +132,7 @@ void Memory::setEndtime(unsigned long cc, unsigned long inc) {
2172 intreq_.setEventTime<intevent_end>(cc + (inc << isDoubleSpeed()));
2175 -void Memory::updateSerial(unsigned long const cc) {
2176 +void Memory::updateSerial(unsigned const cc) {
2177 if (intreq_.eventTime(intevent_serial) != disabled_time) {
2178 if (intreq_.eventTime(intevent_serial) <= cc) {
2179 ioamhram_[0x101] = (((ioamhram_[0x101] + 1) << serialCnt_) - 1) & 0xFF;
2180 @@ -143,18 +148,18 @@ void Memory::updateSerial(unsigned long const cc) {
2184 -void Memory::updateTimaIrq(unsigned long cc) {
2185 +void Memory::updateTimaIrq(unsigned cc) {
2186 while (intreq_.eventTime(intevent_tima) <= cc)
2187 tima_.doIrqEvent(TimaInterruptRequester(intreq_));
2190 -void Memory::updateIrqs(unsigned long cc) {
2191 +void Memory::updateIrqs(unsigned cc) {
2192 updateSerial(cc);
2193 updateTimaIrq(cc);
2194 lcd_.update(cc);
2197 -unsigned long Memory::event(unsigned long cc) {
2198 +unsigned Memory::event(unsigned cc) {
2199 if (lastOamDmaUpdate_ != disabled_time)
2200 updateOamDma(cc);
2202 @@ -177,10 +182,10 @@ unsigned long Memory::event(unsigned long cc) {
2203 case intevent_blit:
2205 bool const lcden = ioamhram_[0x140] & lcdc_en;
2206 - unsigned long blitTime = intreq_.eventTime(intevent_blit);
2207 + unsigned blitTime = intreq_.eventTime(intevent_blit);
2209 if (lcden | blanklcd_) {
2210 - lcd_.updateScreen(blanklcd_, cc);
2211 + lcd_.updateScreen(blanklcd_, cc, videoBuf_, pitch_);
2212 intreq_.setEventTime<intevent_blit>(disabled_time);
2213 intreq_.setEventTime<intevent_end>(disabled_time);
2215 @@ -198,7 +203,7 @@ unsigned long Memory::event(unsigned long cc) {
2216 break;
2217 case intevent_oam:
2218 intreq_.setEventTime<intevent_oam>(lastOamDmaUpdate_ == disabled_time
2219 - ? static_cast<unsigned long>(disabled_time)
2220 + ? static_cast<unsigned>(disabled_time)
2221 : intreq_.eventTime(intevent_oam) + 0xA0 * 4);
2222 break;
2223 case intevent_dma:
2224 @@ -211,7 +216,7 @@ unsigned long Memory::event(unsigned long cc) {
2226 ackDmaReq(intreq_);
2228 - if ((static_cast<unsigned long>(dmaDest) + length) & 0x10000) {
2229 + if ((static_cast<unsigned>(dmaDest) + length) & 0x10000) {
2230 length = 0x10000 - dmaDest;
2231 ioamhram_[0x155] |= 0x80;
2233 @@ -222,7 +227,7 @@ unsigned long Memory::event(unsigned long cc) {
2234 dmaLength = 0;
2237 - unsigned long lOamDmaUpdate = lastOamDmaUpdate_;
2238 + unsigned lOamDmaUpdate = lastOamDmaUpdate_;
2239 lastOamDmaUpdate_ = disabled_time;
2241 while (length--) {
2242 @@ -304,7 +309,7 @@ unsigned long Memory::event(unsigned long cc) {
2243 return cc;
2246 -unsigned long Memory::stop(unsigned long cc) {
2247 +unsigned Memory::stop(unsigned cc) {
2248 cc += 4 + 4 * isDoubleSpeed();
2250 if (ioamhram_[0x14D] & isCgb()) {
2251 @@ -328,29 +333,29 @@ unsigned long Memory::stop(unsigned long cc) {
2252 return cc;
2255 -static void decCycles(unsigned long &counter, unsigned long dec) {
2256 +static void decCycles(unsigned &counter, unsigned dec) {
2257 if (counter != disabled_time)
2258 counter -= dec;
2261 -void Memory::decEventCycles(IntEventId eventId, unsigned long dec) {
2262 +void Memory::decEventCycles(IntEventId eventId, unsigned dec) {
2263 if (intreq_.eventTime(eventId) != disabled_time)
2264 intreq_.setEventTime(eventId, intreq_.eventTime(eventId) - dec);
2267 -unsigned long Memory::resetCounters(unsigned long cc) {
2268 +unsigned Memory::resetCounters(unsigned cc) {
2269 if (lastOamDmaUpdate_ != disabled_time)
2270 updateOamDma(cc);
2272 updateIrqs(cc);
2275 - unsigned long divinc = (cc - divLastUpdate_) >> 8;
2276 + unsigned divinc = (cc - divLastUpdate_) >> 8;
2277 ioamhram_[0x104] = (ioamhram_[0x104] + divinc) & 0xFF;
2278 divLastUpdate_ += divinc << 8;
2281 - unsigned long const dec = cc < 0x10000
2282 + unsigned const dec = cc < 0x10000
2284 : (cc & ~0x7FFFul) - 0x8000;
2285 decCycles(divLastUpdate_, dec);
2286 @@ -361,7 +366,7 @@ unsigned long Memory::resetCounters(unsigned long cc) {
2287 decEventCycles(intevent_end, dec);
2288 decEventCycles(intevent_unhalt, dec);
2290 - unsigned long const oldCC = cc;
2291 + unsigned const oldCC = cc;
2292 cc -= dec;
2293 intreq_.resetCc(oldCC, cc);
2294 tima_.resetCc(oldCC, cc, TimaInterruptRequester(intreq_));
2295 @@ -388,7 +393,7 @@ void Memory::updateInput() {
2296 ioamhram_[0x100] &= button;
2299 -void Memory::updateOamDma(unsigned long const cc) {
2300 +void Memory::updateOamDma(unsigned const cc) {
2301 unsigned char const *const oamDmaSrc = oamDmaSrcPtr();
2302 unsigned cycles = (cc - lastOamDmaUpdate_) >> 2;
2304 @@ -441,17 +446,17 @@ unsigned char const * Memory::oamDmaSrcPtr() const {
2305 return ioamhram_[0x146] == 0xFF && !isCgb() ? oamDmaSrcZero() : cart_.rdisabledRam();
2308 -void Memory::startOamDma(unsigned long cc) {
2309 +void Memory::startOamDma(unsigned cc) {
2310 lcd_.oamChange(cart_.rdisabledRam(), cc);
2313 -void Memory::endOamDma(unsigned long cc) {
2314 +void Memory::endOamDma(unsigned cc) {
2315 oamDmaPos_ = 0xFE;
2316 cart_.setOamDmaSrc(oam_dma_src_off);
2317 lcd_.oamChange(ioamhram_, cc);
2320 -unsigned Memory::nontrivial_ff_read(unsigned const p, unsigned long const cc) {
2321 +unsigned Memory::nontrivial_ff_read(unsigned const p, unsigned const cc) {
2322 if (lastOamDmaUpdate_ != disabled_time)
2323 updateOamDma(cc);
2325 @@ -465,7 +470,7 @@ unsigned Memory::nontrivial_ff_read(unsigned const p, unsigned long const cc) {
2326 break;
2327 case 0x04:
2329 - unsigned long divcycles = (cc - divLastUpdate_) >> 8;
2330 + unsigned divcycles = (cc - divLastUpdate_) >> 8;
2331 ioamhram_[0x104] = (ioamhram_[0x104] + divcycles) & 0xFF;
2332 divLastUpdate_ += divcycles << 8;
2334 @@ -545,7 +550,7 @@ static bool isInOamDmaConflictArea(OamDmaSrc const oamDmaSrc, unsigned const p,
2335 && p - a[oamDmaSrc].exceptAreaLower >= a[oamDmaSrc].exceptAreaWidth;
2338 -unsigned Memory::nontrivial_read(unsigned const p, unsigned long const cc) {
2339 +unsigned Memory::nontrivial_read(unsigned const p, unsigned const cc) {
2340 if (p < 0xFF80) {
2341 if (lastOamDmaUpdate_ != disabled_time) {
2342 updateOamDma(cc);
2343 @@ -585,7 +590,7 @@ unsigned Memory::nontrivial_read(unsigned const p, unsigned long const cc) {
2344 return ioamhram_[p - 0xFE00];
2347 -void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long const cc) {
2348 +void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned const cc) {
2349 if (lastOamDmaUpdate_ != disabled_time)
2350 updateOamDma(cc);
2352 @@ -1005,7 +1010,7 @@ void Memory::nontrivial_ff_write(unsigned const p, unsigned data, unsigned long
2353 ioamhram_[p + 0x100] = data;
2356 -void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned long const cc) {
2357 +void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned const cc) {
2358 if (lastOamDmaUpdate_ != disabled_time) {
2359 updateOamDma(cc);
2361 @@ -1043,20 +1048,53 @@ void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned lo
2362 ioamhram_[p - 0xFE00] = data;
2365 -LoadRes Memory::loadROM(std::string const &romfile, bool const forceDmg, bool const multicartCompat) {
2366 - if (LoadRes const fail = cart_.loadROM(romfile, forceDmg, multicartCompat))
2367 - return fail;
2369 +void Memory::postLoadRom()
2371 psg_.init(cart_.isCgb());
2372 lcd_.reset(ioamhram_, cart_.vramdata(), cart_.isCgb());
2373 interrupter_.setGameShark(std::string());
2376 +LoadRes Memory::loadROM(std::string const &romfile, bool const forceDmg, bool const multicartCompat) {
2377 + if (LoadRes const fail = cart_.loadROM(romfile, forceDmg, multicartCompat))
2378 + return fail;
2379 + postLoadRom();
2380 return LOADRES_OK;
2383 -std::size_t Memory::fillSoundBuffer(unsigned long cc) {
2384 +LoadRes Memory::loadROM(const unsigned char* image, size_t isize, const bool forceDmg, const bool multicartCompat) {
2385 + if (LoadRes fail = cart_.loadROM(image, isize, forceDmg, multicartCompat))
2386 + return fail;
2387 + postLoadRom();
2388 + return LOADRES_OK;
2391 +unsigned Memory::fillSoundBuffer(unsigned cc) {
2392 psg_.generateSamples(cc, isDoubleSpeed());
2393 return psg_.fillBuffer();
2396 +void Memory::setDmgPaletteColor(unsigned palNum, unsigned colorNum, uint_least32_t rgb32) {
2397 + lcd_.setDmgPaletteColor(palNum, colorNum, rgb32);
2400 +void Memory::loadOrSave(loadsave& state)
2402 + state(ioamhram_, 0x200);
2403 + //Don't save getInput, it has no state.
2404 + state(divLastUpdate_);
2405 + state(lastOamDmaUpdate_);
2406 + intreq_.loadOrSave(state);
2407 + cart_.loadOrSave(state);
2408 + tima_.loadOrSave(state);
2409 + lcd_.loadOrSave(state);
2410 + psg_.loadOrSave(state);
2411 + interrupter_.loadOrSave(state);
2412 + state(dmaSource_);
2413 + state(dmaDestination_);
2414 + state(oamDmaPos_);
2415 + state(serialCnt_);
2416 + state(blanklcd_);
2420 diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h
2421 index e612dc3..a531930 100644
2422 --- a/libgambatte/src/memory.h
2423 +++ b/libgambatte/src/memory.h
2424 @@ -19,6 +19,10 @@
2425 #ifndef MEMORY_H
2426 #define MEMORY_H
2429 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
2430 +// - Make it rerecording-friendly.
2432 #include "mem/cartridge.h"
2433 #include "interrupter.h"
2434 #include "pakinfo.h"
2435 @@ -33,12 +37,13 @@ class FilterInfo;
2437 class Memory {
2438 public:
2439 - explicit Memory(Interrupter const &interrupter);
2440 + explicit Memory(Interrupter const &interrupter, time_t (**gettime)());
2441 bool loaded() const { return cart_.loaded(); }
2442 char const * romTitle() const { return cart_.romTitle(); }
2443 PakInfo const pakInfo(bool multicartCompat) const { return cart_.pakInfo(multicartCompat); }
2444 void setStatePtrs(SaveState &state);
2445 - unsigned long saveState(SaveState &state, unsigned long cc);
2446 + unsigned saveState(SaveState &state, unsigned cc);
2447 + void loadOrSave(loadsave& state);
2448 void loadState(SaveState const &state);
2449 void loadSavedata() { cart_.loadSavedata(); }
2450 void saveSavedata() { cart_.saveSavedata(); }
2451 @@ -48,14 +53,14 @@ public:
2452 lcd_.setOsdElement(osdElement);
2455 - unsigned long stop(unsigned long cycleCounter);
2456 + unsigned stop(unsigned cycleCounter);
2457 bool isCgb() const { return lcd_.isCgb(); }
2458 bool ime() const { return intreq_.ime(); }
2459 bool halted() const { return intreq_.halted(); }
2460 - unsigned long nextEventTime() const { return intreq_.minEventTime(); }
2461 + unsigned nextEventTime() const { return intreq_.minEventTime(); }
2462 bool isActive() const { return intreq_.eventTime(intevent_end) != disabled_time; }
2464 - long cyclesSinceBlit(unsigned long cc) const {
2465 + signed cyclesSinceBlit(unsigned cc) const {
2466 if (cc < intreq_.eventTime(intevent_blit))
2467 return -1;
2469 @@ -63,48 +68,55 @@ public:
2472 void halt() { intreq_.halt(); }
2473 - void ei(unsigned long cycleCounter) { if (!ime()) { intreq_.ei(cycleCounter); } }
2474 + void ei(unsigned cycleCounter) { if (!ime()) { intreq_.ei(cycleCounter); } }
2475 void di() { intreq_.di(); }
2477 - unsigned ff_read(unsigned p, unsigned long cc) {
2478 + unsigned ff_read(unsigned p, unsigned cc) {
2479 return p < 0x80 ? nontrivial_ff_read(p, cc) : ioamhram_[p + 0x100];
2482 - unsigned read(unsigned p, unsigned long cc) {
2483 + unsigned read(unsigned p, unsigned cc) {
2484 return cart_.rmem(p >> 12) ? cart_.rmem(p >> 12)[p] : nontrivial_read(p, cc);
2487 - void write(unsigned p, unsigned data, unsigned long cc) {
2488 + void write(unsigned p, unsigned data, unsigned cc) {
2489 if (cart_.wmem(p >> 12)) {
2490 cart_.wmem(p >> 12)[p] = data;
2491 } else
2492 nontrivial_write(p, data, cc);
2495 - void ff_write(unsigned p, unsigned data, unsigned long cc) {
2496 + void ff_write(unsigned p, unsigned data, unsigned cc) {
2497 if (p - 0x80u < 0x7Fu) {
2498 ioamhram_[p + 0x100] = data;
2499 } else
2500 nontrivial_ff_write(p, data, cc);
2503 - unsigned long event(unsigned long cycleCounter);
2504 - unsigned long resetCounters(unsigned long cycleCounter);
2505 - LoadRes loadROM(std::string const &romfile, bool forceDmg, bool multicartCompat);
2506 - void setSaveDir(std::string const &dir) { cart_.setSaveDir(dir); }
2507 - void setInputGetter(InputGetter *getInput) { getInput_ = getInput; }
2508 - void setEndtime(unsigned long cc, unsigned long inc);
2509 - void setSoundBuffer(uint_least32_t *buf) { psg_.setBuffer(buf); }
2510 - std::size_t fillSoundBuffer(unsigned long cc);
2511 + LoadRes loadROM(const std::string &romfile, bool forceDmg, bool multicartCompat);
2512 + LoadRes loadROM(const unsigned char* image, size_t isize, bool forceDmg, bool multicartCompat);
2514 - void setVideoBuffer(uint_least32_t *videoBuf, std::ptrdiff_t pitch) {
2515 - lcd_.setVideoBuffer(videoBuf, pitch);
2516 + void setVideoBuffer(uint_least32_t *const videoBuf, std::ptrdiff_t pitch) {
2517 + videoBuf_ = videoBuf;
2518 + pitch_ = pitch;
2521 - void setDmgPaletteColor(int palNum, int colorNum, unsigned long rgb32) {
2522 - lcd_.setDmgPaletteColor(palNum, colorNum, rgb32);
2524 + void setRtcBase(time_t time) { cart_.setRtcBase(time); }
2525 + time_t getRtcBase() { return cart_.getRtcBase(); }
2526 + std::pair<unsigned char*, size_t> getWorkRam() { return cart_.getWorkRam(); }
2527 + std::pair<unsigned char*, size_t> getSaveRam() { return cart_.getSaveRam(); }
2528 + std::pair<unsigned char*, size_t> getIoRam() { return std::make_pair(ioamhram_, sizeof(ioamhram_)); }
2529 + std::pair<unsigned char*, size_t> getVideoRam() { return cart_.getVideoRam(); };
2531 + unsigned event(unsigned cycleCounter);
2532 + unsigned resetCounters(unsigned cycleCounter);
2533 + void setSaveDir(std::string const &dir) { cart_.setSaveDir(dir); }
2534 + void setInputGetter(InputGetter *getInput) { getInput_ = getInput; }
2535 + void setEndtime(unsigned cc, unsigned inc);
2536 + void setSoundBuffer(uint_least32_t *buf) { psg_.setBuffer(buf); }
2537 + unsigned fillSoundBuffer(unsigned cc);
2539 + void setDmgPaletteColor(unsigned palNum, unsigned colorNum, uint_least32_t rgb32);
2540 void setGameGenie(std::string const &codes) { cart_.setGameGenie(codes); }
2541 void setGameShark(std::string const &codes) { interrupter_.setGameShark(codes); }
2543 @@ -112,8 +124,8 @@ private:
2544 Cartridge cart_;
2545 unsigned char ioamhram_[0x200];
2546 InputGetter *getInput_;
2547 - unsigned long divLastUpdate_;
2548 - unsigned long lastOamDmaUpdate_;
2549 + unsigned divLastUpdate_;
2550 + unsigned lastOamDmaUpdate_;
2551 InterruptRequester intreq_;
2552 Tima tima_;
2553 LCD lcd_;
2554 @@ -124,22 +136,25 @@ private:
2555 unsigned char oamDmaPos_;
2556 unsigned char serialCnt_;
2557 bool blanklcd_;
2558 + uint_least32_t* videoBuf_;
2559 + unsigned pitch_;
2561 void updateInput();
2562 - void decEventCycles(IntEventId eventId, unsigned long dec);
2563 + void decEventCycles(IntEventId eventId, unsigned dec);
2564 void oamDmaInitSetup();
2565 - void updateOamDma(unsigned long cycleCounter);
2566 - void startOamDma(unsigned long cycleCounter);
2567 - void endOamDma(unsigned long cycleCounter);
2568 + void updateOamDma(unsigned cycleCounter);
2569 + void startOamDma(unsigned cycleCounter);
2570 + void endOamDma(unsigned cycleCounter);
2571 unsigned char const * oamDmaSrcPtr() const;
2572 - unsigned nontrivial_ff_read(unsigned p, unsigned long cycleCounter);
2573 - unsigned nontrivial_read(unsigned p, unsigned long cycleCounter);
2574 - void nontrivial_ff_write(unsigned p, unsigned data, unsigned long cycleCounter);
2575 - void nontrivial_write(unsigned p, unsigned data, unsigned long cycleCounter);
2576 - void updateSerial(unsigned long cc);
2577 - void updateTimaIrq(unsigned long cc);
2578 - void updateIrqs(unsigned long cc);
2579 + unsigned nontrivial_ff_read(unsigned p, unsigned cycleCounter);
2580 + unsigned nontrivial_read(unsigned p, unsigned cycleCounter);
2581 + void nontrivial_ff_write(unsigned p, unsigned data, unsigned cycleCounter);
2582 + void nontrivial_write(unsigned p, unsigned data, unsigned cycleCounter);
2583 + void updateSerial(unsigned cc);
2584 + void updateTimaIrq(unsigned cc);
2585 + void updateIrqs(unsigned cc);
2586 bool isDoubleSpeed() const { return lcd_.isDoubleSpeed(); }
2587 + void postLoadRom();
2591 diff --git a/libgambatte/src/minkeeper.h b/libgambatte/src/minkeeper.h
2592 index 7ac5eea..f37edef 100644
2593 --- a/libgambatte/src/minkeeper.h
2594 +++ b/libgambatte/src/minkeeper.h
2595 @@ -19,7 +19,12 @@
2596 #ifndef MINKEEPER_H
2597 #define MINKEEPER_H
2600 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
2601 +// - Make it rerecording-friendly.
2603 #include <algorithm>
2604 +#include "loadsave.h"
2606 namespace MinKeeperUtil {
2607 template<int n> struct CeiledLog2 { enum { r = 1 + CeiledLog2<(n + 1) / 2>::r }; };
2608 @@ -39,22 +44,29 @@ template<template<int> class T> struct Sum<T,0> { enum { r = 0 }; };
2609 template<int ids>
2610 class MinKeeper {
2611 public:
2612 - explicit MinKeeper(unsigned long initValue = 0xFFFFFFFF);
2613 + explicit MinKeeper(unsigned initValue = 0xFFFFFFFF);
2614 int min() const { return a_[0]; }
2615 - unsigned long minValue() const { return minValue_; }
2616 + unsigned minValue() const { return minValue_; }
2618 template<int id>
2619 - void setValue(unsigned long cnt) {
2620 + void setValue(unsigned cnt) {
2621 values_[id] = cnt;
2622 updateValue<id / 2>(*this);
2625 - void setValue(int id, unsigned long cnt) {
2626 + void setValue(int id, unsigned cnt) {
2627 values_[id] = cnt;
2628 updateValueLut.call(id >> 1, *this);
2631 - unsigned long value(int id) const { return values_[id]; }
2632 + unsigned value(int id) const { return values_[id]; }
2634 + void loadOrSave(gambatte::loadsave& state) {
2635 + state(values_, ids);
2636 + state(minValue_);
2637 + //updateValueLut is constant for our purposes.
2638 + state(a_, Sum<levels>::r);
2641 private:
2642 enum { levels = MinKeeperUtil::CeiledLog2<ids>::r };
2643 @@ -101,8 +113,9 @@ private:
2646 static UpdateValueLut updateValueLut;
2647 - unsigned long values_[ids];
2648 - unsigned long minValue_;
2650 + unsigned values_[ids];
2651 + unsigned minValue_;
2652 int a_[Sum<levels>::r];
2654 template<int id> static void updateValue(MinKeeper<ids> &m);
2655 @@ -111,7 +124,7 @@ private:
2656 template<int ids> typename MinKeeper<ids>::UpdateValueLut MinKeeper<ids>::updateValueLut;
2658 template<int ids>
2659 -MinKeeper<ids>::MinKeeper(unsigned long const initValue) {
2660 +MinKeeper<ids>::MinKeeper(unsigned const initValue) {
2661 std::fill(values_, values_ + ids, initValue);
2663 for (int i = 0; i < Num<levels-1>::r; ++i) {
2664 diff --git a/libgambatte/src/savestate.h b/libgambatte/src/savestate.h
2665 index 52a8945..6ca7bc5 100644
2666 --- a/libgambatte/src/savestate.h
2667 +++ b/libgambatte/src/savestate.h
2668 @@ -19,6 +19,11 @@
2669 #ifndef SAVESTATE_H
2670 #define SAVESTATE_H
2673 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
2674 +// - Make it rerecording-friendly.
2676 +#include <ctime>
2677 #include <cstddef>
2679 namespace gambatte {
2680 @@ -35,7 +40,7 @@ struct SaveState {
2681 void set(T *p, std::size_t size) { ptr = p; size_ = size; }
2683 friend class SaverList;
2684 - friend void setInitState(SaveState &, bool, bool);
2685 + friend void setInitState(SaveState &, bool, bool, time_t);
2687 private:
2688 T *ptr;
2689 @@ -43,7 +48,7 @@ struct SaveState {
2692 struct CPU {
2693 - unsigned long cycleCounter;
2694 + unsigned cycleCounter;
2695 unsigned short pc;
2696 unsigned short sp;
2697 unsigned char a;
2698 @@ -62,13 +67,13 @@ struct SaveState {
2699 Ptr<unsigned char> sram;
2700 Ptr<unsigned char> wram;
2701 Ptr<unsigned char> ioamhram;
2702 - unsigned long divLastUpdate;
2703 - unsigned long timaLastUpdate;
2704 - unsigned long tmatime;
2705 - unsigned long nextSerialtime;
2706 - unsigned long lastOamDmaUpdate;
2707 - unsigned long minIntTime;
2708 - unsigned long unhaltTime;
2709 + unsigned divLastUpdate;
2710 + unsigned timaLastUpdate;
2711 + unsigned tmatime;
2712 + unsigned nextSerialtime;
2713 + unsigned lastOamDmaUpdate;
2714 + unsigned minIntTime;
2715 + unsigned unhaltTime;
2716 unsigned short rombank;
2717 unsigned short dmaSource;
2718 unsigned short dmaDestination;
2719 @@ -88,8 +93,8 @@ struct SaveState {
2720 Ptr<unsigned char> oamReaderBuf;
2721 Ptr<bool> oamReaderSzbuf;
2723 - unsigned long videoCycles;
2724 - unsigned long enableDisplayM0Time;
2725 + unsigned videoCycles;
2726 + unsigned enableDisplayM0Time;
2727 unsigned short lastM0Time;
2728 unsigned short nextM0Irq;
2729 unsigned short tileword;
2730 @@ -118,24 +123,24 @@ struct SaveState {
2732 struct SPU {
2733 struct Duty {
2734 - unsigned long nextPosUpdate;
2735 + unsigned nextPosUpdate;
2736 unsigned char nr3;
2737 unsigned char pos;
2740 struct Env {
2741 - unsigned long counter;
2742 + unsigned counter;
2743 unsigned char volume;
2746 struct LCounter {
2747 - unsigned long counter;
2748 + unsigned counter;
2749 unsigned short lengthCounter;
2752 struct {
2753 struct {
2754 - unsigned long counter;
2755 + unsigned counter;
2756 unsigned short shadow;
2757 unsigned char nr0;
2758 bool negging;
2759 @@ -158,8 +163,8 @@ struct SaveState {
2760 struct {
2761 Ptr<unsigned char> waveRam;
2762 LCounter lcounter;
2763 - unsigned long waveCounter;
2764 - unsigned long lastReadTime;
2765 + unsigned waveCounter;
2766 + unsigned lastReadTime;
2767 unsigned char nr3;
2768 unsigned char nr4;
2769 unsigned char wavePos;
2770 @@ -169,7 +174,7 @@ struct SaveState {
2772 struct {
2773 struct {
2774 - unsigned long counter;
2775 + unsigned counter;
2776 unsigned short reg;
2777 } lfsr;
2778 Env env;
2779 @@ -178,12 +183,12 @@ struct SaveState {
2780 bool master;
2781 } ch4;
2783 - unsigned long cycleCounter;
2784 + unsigned cycleCounter;
2785 } spu;
2787 struct RTC {
2788 - unsigned long baseTime;
2789 - unsigned long haltTime;
2790 + unsigned baseTime;
2791 + unsigned haltTime;
2792 unsigned char dataDh;
2793 unsigned char dataDl;
2794 unsigned char dataH;
2795 diff --git a/libgambatte/src/sound.cpp b/libgambatte/src/sound.cpp
2796 index d02759c..9824f96 100644
2797 --- a/libgambatte/src/sound.cpp
2798 +++ b/libgambatte/src/sound.cpp
2799 @@ -21,6 +21,10 @@
2800 #include <algorithm>
2801 #include <cstring>
2804 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
2805 +// - Make it rerecording-friendly.
2808 Frame Sequencer
2810 @@ -89,7 +93,7 @@ void PSG::loadState(SaveState const &state) {
2811 enabled_ = state.mem.ioamhram.get()[0x126] >> 7 & 1;
2814 -void PSG::accumulateChannels(unsigned long const cycles) {
2815 +void PSG::accumulateChannels(unsigned const cycles) {
2816 uint_least32_t *const buf = buffer_ + bufferPos_;
2817 std::memset(buf, 0, cycles * sizeof *buf);
2818 ch1_.update(buf, soVol_, cycles);
2819 @@ -98,8 +102,8 @@ void PSG::accumulateChannels(unsigned long const cycles) {
2820 ch4_.update(buf, soVol_, cycles);
2823 -void PSG::generateSamples(unsigned long const cycleCounter, bool const doubleSpeed) {
2824 - unsigned long const cycles = (cycleCounter - lastUpdate_) >> (1 + doubleSpeed);
2825 +void PSG::generateSamples(unsigned const cycleCounter, bool const doubleSpeed) {
2826 + unsigned const cycles = (cycleCounter - lastUpdate_) >> (1 + doubleSpeed);
2827 lastUpdate_ += cycles << (1 + doubleSpeed);
2829 if (cycles)
2830 @@ -108,12 +112,12 @@ void PSG::generateSamples(unsigned long const cycleCounter, bool const doubleSpe
2831 bufferPos_ += cycles;
2834 -void PSG::resetCounter(unsigned long newCc, unsigned long oldCc, bool doubleSpeed) {
2835 +void PSG::resetCounter(unsigned newCc, unsigned oldCc, bool doubleSpeed) {
2836 generateSamples(oldCc, doubleSpeed);
2837 lastUpdate_ = newCc - (oldCc - lastUpdate_);
2840 -std::size_t PSG::fillBuffer() {
2841 +unsigned PSG::fillBuffer() {
2842 uint_least32_t sum = rsum_;
2843 uint_least32_t *b = buffer_;
2844 std::size_t n = bufferPos_;
2845 @@ -164,8 +168,8 @@ static bool isBigEndianSampleOrder() {
2846 return u.uc[0];
2849 -static unsigned long so1Mul() { return isBigEndianSampleOrder() ? 0x00000001 : 0x00010000; }
2850 -static unsigned long so2Mul() { return isBigEndianSampleOrder() ? 0x00010000 : 0x00000001; }
2851 +static unsigned so1Mul() { return isBigEndianSampleOrder() ? 0x00000001 : 0x00010000; }
2852 +static unsigned so2Mul() { return isBigEndianSampleOrder() ? 0x00010000 : 0x00000001; }
2854 void PSG::setSoVolume(unsigned nr50) {
2855 soVol_ = ((nr50 & 0x7) + 1) * so1Mul() * 64
2856 @@ -173,7 +177,7 @@ void PSG::setSoVolume(unsigned nr50) {
2859 void PSG::mapSo(unsigned nr51) {
2860 - unsigned long so = nr51 * so1Mul() + (nr51 >> 4) * so2Mul();
2861 + unsigned so = nr51 * so1Mul() + (nr51 >> 4) * so2Mul();
2862 ch1_.setSo((so & 0x00010001) * 0xFFFF);
2863 ch2_.setSo((so >> 1 & 0x00010001) * 0xFFFF);
2864 ch3_.setSo((so >> 2 & 0x00010001) * 0xFFFF);
2865 @@ -187,4 +191,17 @@ unsigned PSG::getStatus() const {
2866 | ch4_.isActive() << 3;
2869 +void PSG::loadOrSave(loadsave& state)
2871 + ch1_.loadOrSave(state);
2872 + ch2_.loadOrSave(state);
2873 + ch3_.loadOrSave(state);
2874 + ch4_.loadOrSave(state);
2875 + state(lastUpdate_);
2876 + state(soVol_);
2877 + state(rsum_);
2878 + state(bufferPos_);
2879 + state(enabled_);
2883 diff --git a/libgambatte/src/sound.h b/libgambatte/src/sound.h
2884 index 6c9ce33..d7009f0 100644
2885 --- a/libgambatte/src/sound.h
2886 +++ b/libgambatte/src/sound.h
2887 @@ -19,10 +19,15 @@
2888 #ifndef SOUND_H
2889 #define SOUND_H
2892 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
2893 +// - Make it rerecording-friendly.
2895 #include "sound/channel1.h"
2896 #include "sound/channel2.h"
2897 #include "sound/channel3.h"
2898 #include "sound/channel4.h"
2899 +#include "loadsave.h"
2901 namespace gambatte {
2903 @@ -34,10 +39,11 @@ public:
2904 void setStatePtrs(SaveState &state);
2905 void saveState(SaveState &state);
2906 void loadState(SaveState const &state);
2907 + void loadOrSave(loadsave& state);
2909 - void generateSamples(unsigned long cycleCounter, bool doubleSpeed);
2910 - void resetCounter(unsigned long newCc, unsigned long oldCc, bool doubleSpeed);
2911 - std::size_t fillBuffer();
2912 + void generateSamples(unsigned cycleCounter, bool doubleSpeed);
2913 + void resetCounter(unsigned newCc, unsigned oldCc, bool doubleSpeed);
2914 + unsigned fillBuffer();
2915 void setBuffer(uint_least32_t *buf) { buffer_ = buf; bufferPos_ = 0; }
2917 bool isEnabled() const { return enabled_; }
2918 @@ -77,13 +83,13 @@ private:
2919 Channel3 ch3_;
2920 Channel4 ch4_;
2921 uint_least32_t *buffer_;
2922 - std::size_t bufferPos_;
2923 - unsigned long lastUpdate_;
2924 - unsigned long soVol_;
2925 + unsigned lastUpdate_;
2926 + unsigned soVol_;
2927 + unsigned bufferPos_;
2928 uint_least32_t rsum_;
2929 bool enabled_;
2931 - void accumulateChannels(unsigned long cycles);
2932 + void accumulateChannels(unsigned cycles);
2936 diff --git a/libgambatte/src/sound/channel1.cpp b/libgambatte/src/sound/channel1.cpp
2937 index 182b1a8..c517965 100644
2938 --- a/libgambatte/src/sound/channel1.cpp
2939 +++ b/libgambatte/src/sound/channel1.cpp
2940 @@ -20,6 +20,10 @@
2941 #include "../savestate.h"
2942 #include <algorithm>
2945 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
2946 +// - Make it rerecording-friendly.
2948 namespace gambatte {
2950 Channel1::SweepUnit::SweepUnit(MasterDisabler &disabler, DutyUnit &dutyUnit)
2951 @@ -47,7 +51,7 @@ unsigned Channel1::SweepUnit::calcFreq() {
2954 void Channel1::SweepUnit::event() {
2955 - unsigned long const period = nr0_ >> 4 & 0x07;
2956 + unsigned const period = nr0_ >> 4 & 0x07;
2958 if (period) {
2959 unsigned const freq = calcFreq();
2960 @@ -70,7 +74,7 @@ void Channel1::SweepUnit::nr0Change(unsigned newNr0) {
2961 nr0_ = newNr0;
2964 -void Channel1::SweepUnit::nr4Init(unsigned long const cc) {
2965 +void Channel1::SweepUnit::nr4Init(unsigned const cc) {
2966 negging_ = false;
2967 shadow_ = dutyUnit_.freq();
2969 @@ -168,7 +172,7 @@ void Channel1::setNr4(unsigned const data) {
2970 setEvent();
2973 -void Channel1::setSo(unsigned long soMask) {
2974 +void Channel1::setSo(unsigned soMask) {
2975 soMask_ = soMask;
2976 staticOutputTest_(cycleCounter_);
2977 setEvent();
2978 @@ -212,17 +216,17 @@ void Channel1::loadState(SaveState const &state) {
2979 master_ = state.spu.ch1.master;
2982 -void Channel1::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cycles) {
2983 - unsigned long const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
2984 - unsigned long const outLow = outBase * (0 - 15ul);
2985 - unsigned long const endCycles = cycleCounter_ + cycles;
2986 +void Channel1::update(uint_least32_t *buf, unsigned const soBaseVol, unsigned cycles) {
2987 + unsigned const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
2988 + unsigned const outLow = outBase * (0 - 15ul);
2989 + unsigned const endCycles = cycleCounter_ + cycles;
2991 for (;;) {
2992 - unsigned long const outHigh = master_
2993 + unsigned const outHigh = master_
2994 ? outBase * (envelopeUnit_.getVolume() * 2 - 15ul)
2995 : outLow;
2996 - unsigned long const nextMajorEvent = std::min(nextEventUnit_->counter(), endCycles);
2997 - unsigned long out = dutyUnit_.isHighState() ? outHigh : outLow;
2998 + unsigned const nextMajorEvent = std::min(nextEventUnit_->counter(), endCycles);
2999 + unsigned out = dutyUnit_.isHighState() ? outHigh : outLow;
3001 while (dutyUnit_.counter() <= nextMajorEvent) {
3002 *buf = out - prevOut_;
3003 @@ -257,4 +261,25 @@ void Channel1::update(uint_least32_t *buf, unsigned long const soBaseVol, unsign
3007 +void Channel1::loadOrSave(loadsave& state) {
3008 + //disableMaster has no state.
3009 + lengthCounter_.loadOrSave(state);
3010 + dutyUnit_.loadOrSave(state);
3011 + envelopeUnit_.loadOrSave(state);
3012 + sweepUnit_.loadOrSave(state);
3014 + state.startEnumeration();
3015 + state.enumerate<SoundUnit*>(nextEventUnit_, NULL, 0);
3016 + state.enumerate<SoundUnit*>(nextEventUnit_, &sweepUnit_, 1);
3017 + state.enumerate<SoundUnit*>(nextEventUnit_, &envelopeUnit_, 2);
3018 + state.enumerate<SoundUnit*>(nextEventUnit_, &lengthCounter_, 3);
3019 + state.endEnumeration();
3021 + state(cycleCounter_);
3022 + state(soMask_);
3023 + state(prevOut_);
3024 + state(nr4_);
3025 + state(master_);
3029 diff --git a/libgambatte/src/sound/channel1.h b/libgambatte/src/sound/channel1.h
3030 index b364811..b80ae24 100644
3031 --- a/libgambatte/src/sound/channel1.h
3032 +++ b/libgambatte/src/sound/channel1.h
3033 @@ -19,12 +19,20 @@
3034 #ifndef SOUND_CHANNEL1_H
3035 #define SOUND_CHANNEL1_H
3038 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
3039 +// - Make it rerecording-friendly.
3041 +#include "gbint.h"
3042 +#include "master_disabler.h"
3043 +#include "length_counter.h"
3044 #include "duty_unit.h"
3045 #include "envelope_unit.h"
3046 #include "gbint.h"
3047 #include "length_counter.h"
3048 #include "master_disabler.h"
3049 #include "static_output_tester.h"
3050 +#include "loadsave.h"
3052 namespace gambatte {
3054 @@ -38,9 +46,10 @@ public:
3055 void setNr2(unsigned data);
3056 void setNr3(unsigned data);
3057 void setNr4(unsigned data);
3058 - void setSo(unsigned long soMask);
3059 + void loadOrSave(loadsave& state);
3060 + void setSo(unsigned soMask);
3061 bool isActive() const { return master_; }
3062 - void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
3063 + void update(uint_least32_t *buf, unsigned soBaseVol, unsigned cycles);
3064 void reset();
3065 void init(bool cgb);
3066 void saveState(SaveState &state);
3067 @@ -52,11 +61,18 @@ private:
3068 SweepUnit(MasterDisabler &disabler, DutyUnit &dutyUnit);
3069 virtual void event();
3070 void nr0Change(unsigned newNr0);
3071 - void nr4Init(unsigned long cycleCounter);
3072 + void nr4Init(unsigned cycleCounter);
3073 void reset();
3074 void saveState(SaveState &state) const;
3075 void loadState(SaveState const &state);
3077 + void loadOrSave(loadsave& state) {
3078 + loadOrSave2(state);
3079 + state(shadow_);
3080 + state(nr0_);
3081 + state(negging_);
3084 private:
3085 MasterDisabler &disableMaster_;
3086 DutyUnit &dutyUnit_;
3087 @@ -76,13 +92,14 @@ private:
3088 EnvelopeUnit envelopeUnit_;
3089 SweepUnit sweepUnit_;
3090 SoundUnit *nextEventUnit_;
3091 - unsigned long cycleCounter_;
3092 - unsigned long soMask_;
3093 - unsigned long prevOut_;
3094 + unsigned cycleCounter_;
3095 + unsigned soMask_;
3096 + unsigned prevOut_;
3097 unsigned char nr4_;
3098 bool master_;
3100 void setEvent();
3105 diff --git a/libgambatte/src/sound/channel2.cpp b/libgambatte/src/sound/channel2.cpp
3106 index 7604b10..f154249 100644
3107 --- a/libgambatte/src/sound/channel2.cpp
3108 +++ b/libgambatte/src/sound/channel2.cpp
3109 @@ -20,6 +20,10 @@
3110 #include "../savestate.h"
3111 #include <algorithm>
3114 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
3115 +// - Make it rerecording-friendly.
3117 namespace gambatte {
3119 Channel2::Channel2()
3120 @@ -76,7 +80,7 @@ void Channel2::setNr4(unsigned const data) {
3121 setEvent();
3124 -void Channel2::setSo(unsigned long soMask) {
3125 +void Channel2::setSo(unsigned soMask) {
3126 soMask_ = soMask;
3127 staticOutputTest_(cycleCounter_);
3128 setEvent();
3129 @@ -116,17 +120,17 @@ void Channel2::loadState(SaveState const &state) {
3130 master_ = state.spu.ch2.master;
3133 -void Channel2::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cycles) {
3134 - unsigned long const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
3135 - unsigned long const outLow = outBase * (0 - 15ul);
3136 - unsigned long const endCycles = cycleCounter_ + cycles;
3137 +void Channel2::update(uint_least32_t *buf, unsigned const soBaseVol, unsigned cycles) {
3138 + unsigned const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
3139 + unsigned const outLow = outBase * (0 - 15ul);
3140 + unsigned const endCycles = cycleCounter_ + cycles;
3142 for (;;) {
3143 - unsigned long const outHigh = master_
3144 + unsigned const outHigh = master_
3145 ? outBase * (envelopeUnit_.getVolume() * 2 - 15ul)
3146 : outLow;
3147 - unsigned long const nextMajorEvent = std::min(nextEventUnit->counter(), endCycles);
3148 - unsigned long out = dutyUnit_.isHighState() ? outHigh : outLow;
3149 + unsigned const nextMajorEvent = std::min(nextEventUnit->counter(), endCycles);
3150 + unsigned out = dutyUnit_.isHighState() ? outHigh : outLow;
3152 while (dutyUnit_.counter() <= nextMajorEvent) {
3153 *buf += out - prevOut_;
3154 @@ -160,4 +164,24 @@ void Channel2::update(uint_least32_t *buf, unsigned long const soBaseVol, unsign
3158 +void Channel2::loadOrSave(loadsave& state)
3160 + //disableMaster has no state.
3161 + lengthCounter_.loadOrSave(state);
3162 + dutyUnit_.loadOrSave(state);
3163 + envelopeUnit_.loadOrSave(state);
3165 + state.startEnumeration();
3166 + state.enumerate<SoundUnit*>(nextEventUnit, NULL, 0);
3167 + state.enumerate<SoundUnit*>(nextEventUnit, &lengthCounter_, 1);
3168 + state.enumerate<SoundUnit*>(nextEventUnit, &envelopeUnit_, 2);
3169 + state.endEnumeration();
3171 + state(cycleCounter_);
3172 + state(soMask_);
3173 + state(prevOut_);
3174 + state(nr4_);
3175 + state(master_);
3179 diff --git a/libgambatte/src/sound/channel2.h b/libgambatte/src/sound/channel2.h
3180 index 02833aa..193c520 100644
3181 --- a/libgambatte/src/sound/channel2.h
3182 +++ b/libgambatte/src/sound/channel2.h
3183 @@ -24,6 +24,11 @@
3184 #include "gbint.h"
3185 #include "length_counter.h"
3186 #include "static_output_tester.h"
3187 +#include "loadsave.h"
3190 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
3191 +// - Make it rerecording-friendly.
3193 namespace gambatte {
3195 @@ -36,9 +41,10 @@ public:
3196 void setNr2(unsigned data);
3197 void setNr3(unsigned data);
3198 void setNr4(unsigned data);
3199 - void setSo(unsigned long soMask);
3200 + void loadOrSave(loadsave& state);
3201 + void setSo(unsigned soMask);
3202 bool isActive() const { return master_; }
3203 - void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
3204 + void update(uint_least32_t *buf, unsigned soBaseVol, unsigned cycles);
3205 void reset();
3206 void init(bool cgb);
3207 void saveState(SaveState &state);
3208 @@ -53,9 +59,9 @@ private:
3209 DutyUnit dutyUnit_;
3210 EnvelopeUnit envelopeUnit_;
3211 SoundUnit *nextEventUnit;
3212 - unsigned long cycleCounter_;
3213 - unsigned long soMask_;
3214 - unsigned long prevOut_;
3215 + unsigned cycleCounter_;
3216 + unsigned soMask_;
3217 + unsigned prevOut_;
3218 unsigned char nr4_;
3219 bool master_;
3221 diff --git a/libgambatte/src/sound/channel3.cpp b/libgambatte/src/sound/channel3.cpp
3222 index a582b0c..c583949 100644
3223 --- a/libgambatte/src/sound/channel3.cpp
3224 +++ b/libgambatte/src/sound/channel3.cpp
3225 @@ -21,6 +21,10 @@
3226 #include <algorithm>
3227 #include <cstring>
3230 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
3231 +// - Make it rerecording-friendly.
3233 static inline unsigned toPeriod(unsigned nr3, unsigned nr4) {
3234 return 0x800 - ((nr4 << 8 & 0x700) | nr3);
3236 @@ -79,7 +83,7 @@ void Channel3::setNr4(unsigned const data) {
3240 -void Channel3::setSo(unsigned long soMask) {
3241 +void Channel3::setSo(unsigned soMask) {
3242 soMask_ = soMask;
3245 @@ -127,10 +131,10 @@ void Channel3::loadState(SaveState const &state) {
3246 setNr2(state.mem.ioamhram.get()[0x11C]);
3249 -void Channel3::updateWaveCounter(unsigned long const cc) {
3250 +void Channel3::updateWaveCounter(unsigned const cc) {
3251 if (cc >= waveCounter_) {
3252 unsigned const period = toPeriod(nr3_, nr4_);
3253 - unsigned long const periods = (cc - waveCounter_) / period;
3254 + unsigned const periods = (cc - waveCounter_) / period;
3256 lastReadTime_ = waveCounter_ + periods * period;
3257 waveCounter_ = lastReadTime_ + period;
3258 @@ -142,16 +146,16 @@ void Channel3::updateWaveCounter(unsigned long const cc) {
3262 -void Channel3::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cycles) {
3263 - unsigned long const outBase = nr0_/* & 0x80*/ ? soBaseVol & soMask_ : 0;
3264 +void Channel3::update(uint_least32_t *buf, unsigned const soBaseVol, unsigned cycles) {
3265 + unsigned const outBase = nr0_/* & 0x80*/ ? soBaseVol & soMask_ : 0;
3267 if (outBase && rshift_ != 4) {
3268 - unsigned long const endCycles = cycleCounter_ + cycles;
3269 + unsigned const endCycles = cycleCounter_ + cycles;
3271 for (;;) {
3272 - unsigned long const nextMajorEvent =
3273 + unsigned const nextMajorEvent =
3274 std::min(lengthCounter_.counter(), endCycles);
3275 - unsigned long out = master_
3276 + unsigned out = master_
3277 ? ((sampleBuf_ >> (~wavePos_ << 2 & 4) & 0xF) >> rshift_) * 2 - 15ul
3278 : 0 - 15ul;
3279 out *= outBase;
3280 @@ -184,7 +188,7 @@ void Channel3::update(uint_least32_t *buf, unsigned long const soBaseVol, unsign
3281 break;
3283 } else {
3284 - unsigned long const out = outBase * (0 - 15ul);
3285 + unsigned const out = outBase * (0 - 15ul);
3286 *buf += out - prevOut_;
3287 prevOut_ = out;
3288 cycleCounter_ += cycles;
3289 @@ -208,4 +212,23 @@ void Channel3::update(uint_least32_t *buf, unsigned long const soBaseVol, unsign
3293 +void Channel3::loadOrSave(loadsave& state) {
3294 + state(waveRam_, 0x10);
3295 + //disableMaster has no saveable state.
3296 + lengthCounter_.loadOrSave(state);
3297 + state(cycleCounter_);
3298 + state(soMask_);
3299 + state(prevOut_);
3300 + state(waveCounter_);
3301 + state(lastReadTime_);
3302 + state(nr0_);
3303 + state(nr3_);
3304 + state(nr4_);
3305 + state(wavePos_);
3306 + state(rshift_);
3307 + state(sampleBuf_);
3308 + state(master_);
3309 + state(cgb_);
3313 diff --git a/libgambatte/src/sound/channel3.h b/libgambatte/src/sound/channel3.h
3314 index 2a5e16a..5bd6195 100644
3315 --- a/libgambatte/src/sound/channel3.h
3316 +++ b/libgambatte/src/sound/channel3.h
3317 @@ -19,8 +19,13 @@
3318 #ifndef SOUND_CHANNEL3_H
3319 #define SOUND_CHANNEL3_H
3322 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
3323 +// - Make it rerecording-friendly.
3325 #include "gbint.h"
3326 #include "length_counter.h"
3327 +#include "loadsave.h"
3328 #include "master_disabler.h"
3330 namespace gambatte {
3331 @@ -41,8 +46,8 @@ public:
3332 void setNr2(unsigned data);
3333 void setNr3(unsigned data) { nr3_ = data; }
3334 void setNr4(unsigned data);
3335 - void setSo(unsigned long soMask);
3336 - void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
3337 + void setSo(unsigned soMask);
3338 + void update(uint_least32_t *buf, unsigned soBaseVol, unsigned cycles);
3340 unsigned waveRamRead(unsigned index) const {
3341 if (master_) {
3342 @@ -66,10 +71,11 @@ public:
3343 waveRam_[index] = data;
3346 + void loadOrSave(loadsave& state);
3347 private:
3348 class Ch3MasterDisabler : public MasterDisabler {
3349 public:
3350 - Ch3MasterDisabler(bool &m, unsigned long &wC) : MasterDisabler(m), waveCounter_(wC) {}
3351 + Ch3MasterDisabler(bool &m, unsigned &wC) : MasterDisabler(m), waveCounter_(wC) {}
3353 virtual void operator()() {
3354 MasterDisabler::operator()();
3355 @@ -77,17 +83,17 @@ private:
3358 private:
3359 - unsigned long &waveCounter_;
3360 + unsigned &waveCounter_;
3363 unsigned char waveRam_[0x10];
3364 Ch3MasterDisabler disableMaster_;
3365 LengthCounter lengthCounter_;
3366 - unsigned long cycleCounter_;
3367 - unsigned long soMask_;
3368 - unsigned long prevOut_;
3369 - unsigned long waveCounter_;
3370 - unsigned long lastReadTime_;
3371 + unsigned cycleCounter_;
3372 + unsigned soMask_;
3373 + unsigned prevOut_;
3374 + unsigned waveCounter_;
3375 + unsigned lastReadTime_;
3376 unsigned char nr0_;
3377 unsigned char nr3_;
3378 unsigned char nr4_;
3379 @@ -97,7 +103,7 @@ private:
3380 bool master_;
3381 bool cgb_;
3383 - void updateWaveCounter(unsigned long cc);
3384 + void updateWaveCounter(unsigned cc);
3388 diff --git a/libgambatte/src/sound/channel4.cpp b/libgambatte/src/sound/channel4.cpp
3389 index 7c4bc18..bc0a312 100644
3390 --- a/libgambatte/src/sound/channel4.cpp
3391 +++ b/libgambatte/src/sound/channel4.cpp
3392 @@ -20,7 +20,11 @@
3393 #include "../savestate.h"
3394 #include <algorithm>
3396 -static unsigned long toPeriod(unsigned const nr3) {
3398 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
3399 +// - Make it rerecording-friendly.
3401 +static unsigned toPeriod(unsigned const nr3) {
3402 unsigned s = (nr3 >> 4) + 3;
3403 unsigned r = nr3 & 7;
3405 @@ -42,10 +46,10 @@ Channel4::Lfsr::Lfsr()
3409 -void Channel4::Lfsr::updateBackupCounter(unsigned long const cc) {
3410 +void Channel4::Lfsr::updateBackupCounter(unsigned const cc) {
3411 if (backupCounter_ <= cc) {
3412 - unsigned long const period = toPeriod(nr3_);
3413 - unsigned long periods = (cc - backupCounter_) / period + 1;
3414 + unsigned const period = toPeriod(nr3_);
3415 + unsigned periods = (cc - backupCounter_) / period + 1;
3416 backupCounter_ += periods * period;
3418 if (master_ && nr3_ < 0xE0) {
3419 @@ -70,7 +74,7 @@ void Channel4::Lfsr::updateBackupCounter(unsigned long const cc) {
3423 -void Channel4::Lfsr::reviveCounter(unsigned long cc) {
3424 +void Channel4::Lfsr::reviveCounter(unsigned cc) {
3425 updateBackupCounter(cc);
3426 counter_ = backupCounter_;
3428 @@ -89,12 +93,12 @@ inline void Channel4::Lfsr::event() {
3429 backupCounter_ = counter_;
3432 -void Channel4::Lfsr::nr3Change(unsigned newNr3, unsigned long cc) {
3433 +void Channel4::Lfsr::nr3Change(unsigned newNr3, unsigned cc) {
3434 updateBackupCounter(cc);
3435 nr3_ = newNr3;
3438 -void Channel4::Lfsr::nr4Init(unsigned long cc) {
3439 +void Channel4::Lfsr::nr4Init(unsigned cc) {
3440 disableMaster();
3441 updateBackupCounter(cc);
3442 master_ = true;
3443 @@ -102,19 +106,19 @@ void Channel4::Lfsr::nr4Init(unsigned long cc) {
3444 counter_ = backupCounter_;
3447 -void Channel4::Lfsr::reset(unsigned long cc) {
3448 +void Channel4::Lfsr::reset(unsigned cc) {
3449 nr3_ = 0;
3450 disableMaster();
3451 backupCounter_ = cc + toPeriod(nr3_);
3454 -void Channel4::Lfsr::resetCounters(unsigned long oldCc) {
3455 +void Channel4::Lfsr::resetCounters(unsigned oldCc) {
3456 updateBackupCounter(oldCc);
3457 backupCounter_ -= counter_max;
3458 SoundUnit::resetCounters(oldCc);
3461 -void Channel4::Lfsr::saveState(SaveState &state, unsigned long cc) {
3462 +void Channel4::Lfsr::saveState(SaveState &state, unsigned cc) {
3463 updateBackupCounter(cc);
3464 state.spu.ch4.lfsr.counter = backupCounter_;
3465 state.spu.ch4.lfsr.reg = reg_;
3466 @@ -179,7 +183,7 @@ void Channel4::setNr4(unsigned const data) {
3467 setEvent();
3470 -void Channel4::setSo(unsigned long soMask) {
3471 +void Channel4::setSo(unsigned soMask) {
3472 soMask_ = soMask;
3473 staticOutputTest_(cycleCounter_);
3474 setEvent();
3475 @@ -218,15 +222,15 @@ void Channel4::loadState(SaveState const &state) {
3476 master_ = state.spu.ch4.master;
3479 -void Channel4::update(uint_least32_t *buf, unsigned long const soBaseVol, unsigned long cycles) {
3480 - unsigned long const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
3481 - unsigned long const outLow = outBase * (0 - 15ul);
3482 - unsigned long const endCycles = cycleCounter_ + cycles;
3483 +void Channel4::update(uint_least32_t *buf, unsigned const soBaseVol, unsigned cycles) {
3484 + unsigned const outBase = envelopeUnit_.dacIsOn() ? soBaseVol & soMask_ : 0;
3485 + unsigned const outLow = outBase * (0 - 15ul);
3486 + unsigned const endCycles = cycleCounter_ + cycles;
3488 for (;;) {
3489 - unsigned long const outHigh = outBase * (envelopeUnit_.getVolume() * 2 - 15ul);
3490 - unsigned long const nextMajorEvent = std::min(nextEventUnit_->counter(), endCycles);
3491 - unsigned long out = lfsr_.isHighState() ? outHigh : outLow;
3492 + unsigned const outHigh = outBase * (envelopeUnit_.getVolume() * 2 - 15ul);
3493 + unsigned const nextMajorEvent = std::min(nextEventUnit_->counter(), endCycles);
3494 + unsigned out = lfsr_.isHighState() ? outHigh : outLow;
3496 while (lfsr_.counter() <= nextMajorEvent) {
3497 *buf += out - prevOut_;
3498 @@ -260,4 +264,23 @@ void Channel4::update(uint_least32_t *buf, unsigned long const soBaseVol, unsign
3502 +void Channel4::loadOrSave(loadsave& state) {
3503 + //DisableMaster has no state.
3504 + lengthCounter_.loadOrSave(state);
3505 + envelopeUnit_.loadOrSave(state);
3506 + lfsr_.loadOrSave(state);
3508 + state.startEnumeration();
3509 + state.enumerate<SoundUnit*>(nextEventUnit_, NULL, 0);
3510 + state.enumerate<SoundUnit*>(nextEventUnit_, &lengthCounter_, 1);
3511 + state.enumerate<SoundUnit*>(nextEventUnit_, &envelopeUnit_, 2);
3512 + state.endEnumeration();
3514 + state(cycleCounter_);
3515 + state(soMask_);
3516 + state(prevOut_);
3517 + state(nr4_);
3518 + state(master_);
3522 diff --git a/libgambatte/src/sound/channel4.h b/libgambatte/src/sound/channel4.h
3523 index 9070b59..cb18afa 100644
3524 --- a/libgambatte/src/sound/channel4.h
3525 +++ b/libgambatte/src/sound/channel4.h
3526 @@ -24,6 +24,11 @@
3527 #include "length_counter.h"
3528 #include "master_disabler.h"
3529 #include "static_output_tester.h"
3530 +#include "loadsave.h"
3533 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
3534 +// - Make it rerecording-friendly.
3536 namespace gambatte {
3538 @@ -36,9 +41,10 @@ public:
3539 void setNr2(unsigned data);
3540 void setNr3(unsigned data) { lfsr_.nr3Change(data, cycleCounter_); }
3541 void setNr4(unsigned data);
3542 - void setSo(unsigned long soMask);
3543 + void loadOrSave(loadsave& state);
3544 + void setSo(unsigned soMask);
3545 bool isActive() const { return master_; }
3546 - void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles);
3547 + void update(uint_least32_t *buf, unsigned soBaseVol, unsigned cycles);
3548 void reset();
3549 void init(bool cgb);
3550 void saveState(SaveState &state);
3551 @@ -49,24 +55,31 @@ private:
3552 public:
3553 Lfsr();
3554 virtual void event();
3555 - virtual void resetCounters(unsigned long oldCc);
3556 + void loadOrSave(loadsave& state) {
3557 + loadOrSave2(state);
3558 + state(backupCounter_);
3559 + state(reg_);
3560 + state(nr3_);
3561 + state(master_);
3563 + virtual void resetCounters(unsigned oldCc);
3564 bool isHighState() const { return ~reg_ & 1; }
3565 - void nr3Change(unsigned newNr3, unsigned long cc);
3566 - void nr4Init(unsigned long cc);
3567 - void reset(unsigned long cc);
3568 - void saveState(SaveState &state, unsigned long cc);
3569 + void nr3Change(unsigned newNr3, unsigned cc);
3570 + void nr4Init(unsigned cc);
3571 + void reset(unsigned cc);
3572 + void saveState(SaveState &state, unsigned cc);
3573 void loadState(SaveState const &state);
3574 void disableMaster() { killCounter(); master_ = false; reg_ = 0x7FFF; }
3575 void killCounter() { counter_ = counter_disabled; }
3576 - void reviveCounter(unsigned long cc);
3577 + void reviveCounter(unsigned cc);
3579 private:
3580 - unsigned long backupCounter_;
3581 + unsigned backupCounter_;
3582 unsigned short reg_;
3583 unsigned char nr3_;
3584 bool master_;
3586 - void updateBackupCounter(unsigned long cc);
3587 + void updateBackupCounter(unsigned cc);
3590 class Ch4MasterDisabler : public MasterDisabler {
3591 @@ -86,9 +99,9 @@ private:
3592 EnvelopeUnit envelopeUnit_;
3593 Lfsr lfsr_;
3594 SoundUnit *nextEventUnit_;
3595 - unsigned long cycleCounter_;
3596 - unsigned long soMask_;
3597 - unsigned long prevOut_;
3598 + unsigned cycleCounter_;
3599 + unsigned soMask_;
3600 + unsigned prevOut_;
3601 unsigned char nr4_;
3602 bool master_;
3604 diff --git a/libgambatte/src/sound/duty_unit.cpp b/libgambatte/src/sound/duty_unit.cpp
3605 index df37b66..4258508 100644
3606 --- a/libgambatte/src/sound/duty_unit.cpp
3607 +++ b/libgambatte/src/sound/duty_unit.cpp
3608 @@ -19,6 +19,10 @@
3609 #include "duty_unit.h"
3610 #include <algorithm>
3613 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
3614 +// - Make it rerecording-friendly.
3616 static inline bool toOutState(unsigned duty, unsigned pos) {
3617 static unsigned char const duties[4] = { 0x80, 0x81, 0xE1, 0x7E };
3618 return duties[duty] >> pos & 1;
3619 @@ -40,9 +44,9 @@ DutyUnit::DutyUnit()
3623 -void DutyUnit::updatePos(unsigned long const cc) {
3624 +void DutyUnit::updatePos(unsigned const cc) {
3625 if (cc >= nextPosUpdate_) {
3626 - unsigned long const inc = (cc - nextPosUpdate_) / period_ + 1;
3627 + unsigned const inc = (cc - nextPosUpdate_) / period_ + 1;
3628 nextPosUpdate_ += period_ * inc;
3629 pos_ += inc;
3630 pos_ &= 7;
3631 @@ -68,7 +72,7 @@ void DutyUnit::setCounter() {
3632 counter_ = counter_disabled;
3635 -void DutyUnit::setFreq(unsigned newFreq, unsigned long cc) {
3636 +void DutyUnit::setFreq(unsigned newFreq, unsigned cc) {
3637 updatePos(cc);
3638 period_ = toPeriod(newFreq);
3639 setCounter();
3640 @@ -86,17 +90,17 @@ void DutyUnit::event() {
3641 counter_ += inc;
3644 -void DutyUnit::nr1Change(unsigned newNr1, unsigned long cc) {
3645 +void DutyUnit::nr1Change(unsigned newNr1, unsigned cc) {
3646 updatePos(cc);
3647 setDuty(newNr1);
3648 setCounter();
3651 -void DutyUnit::nr3Change(unsigned newNr3, unsigned long cc) {
3652 +void DutyUnit::nr3Change(unsigned newNr3, unsigned cc) {
3653 setFreq((freq() & 0x700) | newNr3, cc);
3656 -void DutyUnit::nr4Change(unsigned const newNr4, unsigned long const cc) {
3657 +void DutyUnit::nr4Change(unsigned const newNr4, unsigned const cc) {
3658 setFreq((newNr4 << 8 & 0x700) | (freq() & 0xFF), cc);
3660 if (newNr4 & 0x80) {
3661 @@ -112,7 +116,7 @@ void DutyUnit::reset() {
3662 setCounter();
3665 -void DutyUnit::saveState(SaveState::SPU::Duty &dstate, unsigned long const cc) {
3666 +void DutyUnit::saveState(SaveState::SPU::Duty &dstate, unsigned const cc) {
3667 updatePos(cc);
3668 dstate.nextPosUpdate = nextPosUpdate_;
3669 dstate.nr3 = freq() & 0xFF;
3670 @@ -120,7 +124,7 @@ void DutyUnit::saveState(SaveState::SPU::Duty &dstate, unsigned long const cc) {
3673 void DutyUnit::loadState(const SaveState::SPU::Duty &dstate,
3674 - unsigned const nr1, unsigned const nr4, unsigned long const cc) {
3675 + unsigned const nr1, unsigned const nr4, unsigned const cc) {
3676 nextPosUpdate_ = std::max(dstate.nextPosUpdate, cc);
3677 pos_ = dstate.pos & 7;
3678 setDuty(nr1);
3679 @@ -129,7 +133,7 @@ void DutyUnit::loadState(const SaveState::SPU::Duty &dstate,
3680 setCounter();
3683 -void DutyUnit::resetCounters(unsigned long const oldCc) {
3684 +void DutyUnit::resetCounters(unsigned const oldCc) {
3685 if (nextPosUpdate_ == counter_disabled)
3686 return;
3688 @@ -143,11 +147,21 @@ void DutyUnit::killCounter() {
3689 setCounter();
3692 -void DutyUnit::reviveCounter(unsigned long const cc) {
3693 +void DutyUnit::reviveCounter(unsigned const cc) {
3694 updatePos(cc);
3695 high_ = toOutState(duty_, pos_);
3696 enableEvents_ = true;
3697 setCounter();
3700 +void DutyUnit::loadOrSave(loadsave& state) {
3701 + loadOrSave2(state);
3702 + state(nextPosUpdate_);
3703 + state(period_);
3704 + state(pos_);
3705 + state(duty_);
3706 + state(high_);
3707 + state(enableEvents_);
3711 diff --git a/libgambatte/src/sound/duty_unit.h b/libgambatte/src/sound/duty_unit.h
3712 index 7539c1b..a3a565c 100644
3713 --- a/libgambatte/src/sound/duty_unit.h
3714 +++ b/libgambatte/src/sound/duty_unit.h
3715 @@ -19,9 +19,14 @@
3716 #ifndef DUTY_UNIT_H
3717 #define DUTY_UNIT_H
3720 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
3721 +// - Make it rerecording-friendly.
3723 #include "sound_unit.h"
3724 #include "master_disabler.h"
3725 #include "../savestate.h"
3726 +#include "../loadsave.h"
3728 namespace gambatte {
3730 @@ -29,23 +34,25 @@ class DutyUnit : public SoundUnit {
3731 public:
3732 DutyUnit();
3733 virtual void event();
3734 - virtual void resetCounters(unsigned long oldCc);
3735 + virtual void resetCounters(unsigned oldCc);
3736 bool isHighState() const { return high_; }
3737 - void nr1Change(unsigned newNr1, unsigned long cc);
3738 - void nr3Change(unsigned newNr3, unsigned long cc);
3739 - void nr4Change(unsigned newNr4, unsigned long cc);
3740 + void nr1Change(unsigned newNr1, unsigned cc);
3741 + void nr3Change(unsigned newNr3, unsigned cc);
3742 + void nr4Change(unsigned newNr4, unsigned cc);
3743 void reset();
3744 - void saveState(SaveState::SPU::Duty &dstate, unsigned long cc);
3745 - void loadState(SaveState::SPU::Duty const &dstate, unsigned nr1, unsigned nr4, unsigned long cc);
3746 + void saveState(SaveState::SPU::Duty &dstate, unsigned cc);
3747 + void loadState(SaveState::SPU::Duty const &dstate, unsigned nr1, unsigned nr4, unsigned cc);
3748 void killCounter();
3749 - void reviveCounter(unsigned long cc);
3750 + void reviveCounter(unsigned cc);
3752 + void loadOrSave(loadsave& state);
3754 //intended for use by SweepUnit only.
3755 unsigned freq() const { return 2048 - (period_ >> 1); }
3756 - void setFreq(unsigned newFreq, unsigned long cc);
3757 + void setFreq(unsigned newFreq, unsigned cc);
3759 private:
3760 - unsigned long nextPosUpdate_;
3761 + unsigned nextPosUpdate_;
3762 unsigned short period_;
3763 unsigned char pos_;
3764 unsigned char duty_;
3765 @@ -54,7 +61,7 @@ private:
3767 void setCounter();
3768 void setDuty(unsigned nr1);
3769 - void updatePos(unsigned long cc);
3770 + void updatePos(unsigned cc);
3773 class DutyMasterDisabler : public MasterDisabler {
3774 diff --git a/libgambatte/src/sound/envelope_unit.cpp b/libgambatte/src/sound/envelope_unit.cpp
3775 index 248b6b6..67b563c 100644
3776 --- a/libgambatte/src/sound/envelope_unit.cpp
3777 +++ b/libgambatte/src/sound/envelope_unit.cpp
3778 @@ -19,6 +19,10 @@
3779 #include "envelope_unit.h"
3780 #include <algorithm>
3783 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
3784 +// - Make it rerecording-friendly.
3786 namespace gambatte {
3788 EnvelopeUnit::VolOnOffEvent EnvelopeUnit::nullEvent_;
3789 @@ -39,14 +43,14 @@ void EnvelopeUnit::saveState(SaveState::SPU::Env &estate) const {
3790 estate.volume = volume_;
3793 -void EnvelopeUnit::loadState(SaveState::SPU::Env const &estate, unsigned nr2, unsigned long cc) {
3794 +void EnvelopeUnit::loadState(SaveState::SPU::Env const &estate, unsigned nr2, unsigned cc) {
3795 counter_ = std::max(estate.counter, cc);
3796 volume_ = estate.volume;
3797 nr2_ = nr2;
3800 void EnvelopeUnit::event() {
3801 - unsigned long const period = nr2_ & 7;
3802 + unsigned const period = nr2_ & 7;
3804 if (period) {
3805 unsigned newVol = volume_;
3806 @@ -81,9 +85,9 @@ bool EnvelopeUnit::nr2Change(unsigned const newNr2) {
3807 return !(newNr2 & 0xF8);
3810 -bool EnvelopeUnit::nr4Init(unsigned long const cc) {
3811 +bool EnvelopeUnit::nr4Init(unsigned const cc) {
3813 - unsigned long period = nr2_ & 7;
3814 + unsigned period = nr2_ & 7;
3816 if (!period)
3817 period = 8;
3818 @@ -98,4 +102,11 @@ bool EnvelopeUnit::nr4Init(unsigned long const cc) {
3819 return !(nr2_ & 0xF8);
3822 +void EnvelopeUnit::loadOrSave(loadsave& state)
3824 + loadOrSave2(state);
3825 + state(nr2_);
3826 + state(volume_);
3830 diff --git a/libgambatte/src/sound/envelope_unit.h b/libgambatte/src/sound/envelope_unit.h
3831 index e1d092d..133667d 100644
3832 --- a/libgambatte/src/sound/envelope_unit.h
3833 +++ b/libgambatte/src/sound/envelope_unit.h
3834 @@ -19,8 +19,13 @@
3835 #ifndef ENVELOPE_UNIT_H
3836 #define ENVELOPE_UNIT_H
3839 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
3840 +// - Make it rerecording-friendly.
3842 #include "sound_unit.h"
3843 #include "../savestate.h"
3844 +#include "../loadsave.h"
3846 namespace gambatte {
3848 @@ -28,7 +33,7 @@ class EnvelopeUnit : public SoundUnit {
3849 public:
3850 struct VolOnOffEvent {
3851 virtual ~VolOnOffEvent() {}
3852 - virtual void operator()(unsigned long /*cc*/) {}
3853 + virtual void operator()(unsigned /*cc*/) {}
3856 explicit EnvelopeUnit(VolOnOffEvent &volOnOffEvent = nullEvent_);
3857 @@ -36,10 +41,11 @@ public:
3858 bool dacIsOn() const { return nr2_ & 0xF8; }
3859 unsigned getVolume() const { return volume_; }
3860 bool nr2Change(unsigned newNr2);
3861 - bool nr4Init(unsigned long cycleCounter);
3862 + bool nr4Init(unsigned cycleCounter);
3863 void reset();
3864 void saveState(SaveState::SPU::Env &estate) const;
3865 - void loadState(SaveState::SPU::Env const &estate, unsigned nr2, unsigned long cc);
3866 + void loadOrSave(loadsave& state);
3867 + void loadState(SaveState::SPU::Env const &estate, unsigned nr2, unsigned cc);
3869 private:
3870 static VolOnOffEvent nullEvent_;
3871 diff --git a/libgambatte/src/sound/length_counter.cpp b/libgambatte/src/sound/length_counter.cpp
3872 index e4dadcb..9aa3422 100644
3873 --- a/libgambatte/src/sound/length_counter.cpp
3874 +++ b/libgambatte/src/sound/length_counter.cpp
3875 @@ -20,6 +20,10 @@
3876 #include "master_disabler.h"
3877 #include <algorithm>
3880 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
3881 +// - Make it rerecording-friendly.
3883 namespace gambatte {
3885 LengthCounter::LengthCounter(MasterDisabler &disabler, unsigned const mask)
3886 @@ -37,14 +41,14 @@ void LengthCounter::event() {
3887 disableMaster_();
3890 -void LengthCounter::nr1Change(unsigned const newNr1, unsigned const nr4, unsigned long const cc) {
3891 +void LengthCounter::nr1Change(unsigned const newNr1, unsigned const nr4, unsigned const cc) {
3892 lengthCounter_ = (~newNr1 & lengthMask_) + 1;
3893 counter_ = nr4 & 0x40
3894 ? ((cc >> 13) + lengthCounter_) << 13
3895 - : static_cast<unsigned long>(counter_disabled);
3896 + : static_cast<unsigned>(counter_disabled);
3899 -void LengthCounter::nr4Change(unsigned const oldNr4, unsigned const newNr4, unsigned long const cc) {
3900 +void LengthCounter::nr4Change(unsigned const oldNr4, unsigned const newNr4, unsigned const cc) {
3901 if (counter_ != counter_disabled)
3902 lengthCounter_ = (counter_ >> 13) - (cc >> 13);
3904 @@ -79,9 +83,16 @@ void LengthCounter::saveState(SaveState::SPU::LCounter &lstate) const {
3905 lstate.lengthCounter = lengthCounter_;
3908 -void LengthCounter::loadState(SaveState::SPU::LCounter const &lstate, unsigned long const cc) {
3909 +void LengthCounter::loadState(SaveState::SPU::LCounter const &lstate, unsigned const cc) {
3910 counter_ = std::max(lstate.counter, cc);
3911 lengthCounter_ = lstate.lengthCounter;
3914 +void LengthCounter::loadOrSave(loadsave& state)
3916 + loadOrSave2(state);
3917 + state(lengthCounter_);
3918 + state(cgb_);
3922 diff --git a/libgambatte/src/sound/length_counter.h b/libgambatte/src/sound/length_counter.h
3923 index 47f0c96..3311802 100644
3924 --- a/libgambatte/src/sound/length_counter.h
3925 +++ b/libgambatte/src/sound/length_counter.h
3926 @@ -19,8 +19,13 @@
3927 #ifndef LENGTH_COUNTER_H
3928 #define LENGTH_COUNTER_H
3931 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
3932 +// - Make it rerecording-friendly.
3934 #include "sound_unit.h"
3935 #include "../savestate.h"
3936 +#include "../loadsave.h"
3938 namespace gambatte {
3940 @@ -29,12 +34,13 @@ class MasterDisabler;
3941 class LengthCounter : public SoundUnit {
3942 public:
3943 LengthCounter(MasterDisabler &disabler, unsigned lengthMask);
3944 + void loadOrSave(loadsave& state);
3945 virtual void event();
3946 - void nr1Change(unsigned newNr1, unsigned nr4, unsigned long cc);
3947 - void nr4Change(unsigned oldNr4, unsigned newNr4, unsigned long cc);
3948 + void nr1Change(unsigned newNr1, unsigned nr4, unsigned cc);
3949 + void nr4Change(unsigned oldNr4, unsigned newNr4, unsigned cc);
3950 void init(bool cgb);
3951 void saveState(SaveState::SPU::LCounter &lstate) const;
3952 - void loadState(SaveState::SPU::LCounter const &lstate, unsigned long cc);
3953 + void loadState(SaveState::SPU::LCounter const &lstate, unsigned cc);
3955 private:
3956 MasterDisabler &disableMaster_;
3957 diff --git a/libgambatte/src/sound/sound_unit.h b/libgambatte/src/sound/sound_unit.h
3958 index a504ce7..6c503d6 100644
3959 --- a/libgambatte/src/sound/sound_unit.h
3960 +++ b/libgambatte/src/sound/sound_unit.h
3961 @@ -19,6 +19,12 @@
3962 #ifndef SOUND_UNIT_H
3963 #define SOUND_UNIT_H
3966 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
3967 +// - Make it rerecording-friendly.
3969 +#include "../loadsave.h"
3971 namespace gambatte {
3973 class SoundUnit {
3974 @@ -27,17 +33,20 @@ public:
3976 virtual ~SoundUnit() {}
3977 virtual void event() = 0;
3978 + void loadOrSave2(loadsave& state) {
3979 + state(counter_);
3982 - virtual void resetCounters(unsigned long /*oldCc*/) {
3983 + virtual void resetCounters(unsigned /*oldCc*/) {
3984 if (counter_ != counter_disabled)
3985 counter_ -= counter_max;
3988 - unsigned long counter() const { return counter_; }
3989 + unsigned counter() const { return counter_; }
3991 protected:
3992 SoundUnit() : counter_(counter_disabled) {}
3993 - unsigned long counter_;
3994 + unsigned counter_;
3998 diff --git a/libgambatte/src/sound/static_output_tester.h b/libgambatte/src/sound/static_output_tester.h
3999 index 84a1ec8..00c2004 100644
4000 --- a/libgambatte/src/sound/static_output_tester.h
4001 +++ b/libgambatte/src/sound/static_output_tester.h
4002 @@ -19,6 +19,10 @@
4003 #ifndef STATIC_OUTPUT_TESTER_H
4004 #define STATIC_OUTPUT_TESTER_H
4007 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
4008 +// - Make it rerecording-friendly.
4010 #include "envelope_unit.h"
4012 namespace gambatte {
4013 @@ -27,7 +31,7 @@ template<class Channel, class Unit>
4014 class StaticOutputTester : public EnvelopeUnit::VolOnOffEvent {
4015 public:
4016 StaticOutputTester(Channel const &ch, Unit &unit) : ch_(ch), unit_(unit) {}
4017 - void operator()(unsigned long cc);
4018 + void operator()(unsigned cc);
4020 private:
4021 Channel const &ch_;
4022 @@ -35,7 +39,7 @@ private:
4025 template<class Channel, class Unit>
4026 -void StaticOutputTester<Channel, Unit>::operator()(unsigned long cc) {
4027 +void StaticOutputTester<Channel, Unit>::operator()(unsigned cc) {
4028 if (ch_.soMask_ && ch_.master_ && ch_.envelopeUnit_.getVolume())
4029 unit_.reviveCounter(cc);
4030 else
4031 diff --git a/libgambatte/src/state_osd_elements.cpp b/libgambatte/src/state_osd_elements.cpp
4032 index 361ce1f..e74bca8 100644
4033 --- a/libgambatte/src/state_osd_elements.cpp
4034 +++ b/libgambatte/src/state_osd_elements.cpp
4035 @@ -23,6 +23,10 @@
4036 #include <fstream>
4037 #include <cstring>
4040 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
4041 +// - Make it rerecording-friendly.
4043 namespace {
4045 using namespace gambatte;
4046 @@ -72,7 +76,7 @@ ShadedTextOsdElment::ShadedTextOsdElment(unsigned width, const char *txt)
4047 print(pixels + 1 * w() + 1, w(), 0xE0E0E0ul, txt);*/
4049 bitmapfont::print(pixels.get() , w(), ShadeFill(), txt);
4050 - bitmapfont::print(pixels.get() + 1 * w() + 1, w(), 0xE0E0E0ul , txt);
4051 + bitmapfont::print(pixels.get() + 1 * w() + 1, w(), 0xE0E0E0u , txt);
4054 const uint_least32_t* ShadedTextOsdElment::update() {
4055 @@ -132,7 +136,7 @@ SaveStateOsdElement::SaveStateOsdElement(const std::string &fileName, unsigned s
4056 using namespace bitmapfont;
4057 static const char txt[] = { E,m,p,t,bitmapfont::y,0 };
4058 print(pixels + 3 + (StateSaver::ss_height / 2 - bitmapfont::HEIGHT / 2) * StateSaver::ss_width,
4059 - StateSaver::ss_width, 0x808080ul, txt);
4060 + StateSaver::ss_width, 0x808080u, txt);
4064 diff --git a/libgambatte/src/statesaver.cpp b/libgambatte/src/statesaver.cpp
4065 index 198ef05..a1dcb55 100644
4066 --- a/libgambatte/src/statesaver.cpp
4067 +++ b/libgambatte/src/statesaver.cpp
4068 @@ -77,7 +77,7 @@ static void write(std::ofstream &file, unsigned short data) {
4069 file.put(data & 0xFF);
4072 -static void write(std::ofstream &file, unsigned long data) {
4073 +static void write(std::ofstream &file, unsigned data) {
4074 static char const inf[] = { 0x00, 0x00, 0x04 };
4075 file.write(inf, sizeof inf);
4076 put32(file, data);
4077 @@ -130,7 +130,7 @@ static inline void read(std::ifstream &file, unsigned short &data) {
4078 data = read(file) & 0xFFFF;
4081 -static inline void read(std::ifstream &file, unsigned long &data) {
4082 +static inline void read(std::ifstream &file, unsigned &data) {
4083 data = read(file);
4086 diff --git a/libgambatte/src/statesaver.h b/libgambatte/src/statesaver.h
4087 index e62f1ef..89662f6 100644
4088 --- a/libgambatte/src/statesaver.h
4089 +++ b/libgambatte/src/statesaver.h
4090 @@ -19,9 +19,14 @@
4091 #ifndef STATESAVER_H
4092 #define STATESAVER_H
4095 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
4096 +// - Make it rerecording-friendly.
4098 #include "gbint.h"
4099 #include <cstddef>
4100 #include <string>
4101 +#include <vector>
4103 namespace gambatte {
4105 diff --git a/libgambatte/src/tima.cpp b/libgambatte/src/tima.cpp
4106 index 649f24b..bb056ac 100644
4107 --- a/libgambatte/src/tima.cpp
4108 +++ b/libgambatte/src/tima.cpp
4109 @@ -19,6 +19,10 @@
4110 #include "tima.h"
4111 #include "savestate.h"
4114 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
4115 +// - Make it rerecording-friendly.
4117 static unsigned char const timaClock[4] = { 10, 4, 6, 8 };
4119 namespace gambatte {
4120 @@ -44,7 +48,7 @@ void Tima::loadState(SaveState const &state, TimaInterruptRequester timaIrq) {
4121 tma_ = state.mem.ioamhram.get()[0x106];
4122 tac_ = state.mem.ioamhram.get()[0x107];
4124 - unsigned long nextIrqEventTime = disabled_time;
4125 + unsigned nextIrqEventTime = disabled_time;
4126 if (tac_ & 4) {
4127 nextIrqEventTime = tmatime_ != disabled_time && tmatime_ > state.cpu.cycleCounter
4128 ? tmatime_
4129 @@ -54,12 +58,12 @@ void Tima::loadState(SaveState const &state, TimaInterruptRequester timaIrq) {
4130 timaIrq.setNextIrqEventTime(nextIrqEventTime);
4133 -void Tima::resetCc(unsigned long const oldCc, unsigned long const newCc, TimaInterruptRequester timaIrq) {
4134 +void Tima::resetCc(unsigned const oldCc, unsigned const newCc, TimaInterruptRequester timaIrq) {
4135 if (tac_ & 0x04) {
4136 updateIrq(oldCc, timaIrq);
4137 updateTima(oldCc);
4139 - unsigned long const dec = oldCc - newCc;
4140 + unsigned const dec = oldCc - newCc;
4141 lastUpdate_ -= dec;
4142 timaIrq.setNextIrqEventTime(timaIrq.nextIrqEventTime() - dec);
4144 @@ -68,8 +72,8 @@ void Tima::resetCc(unsigned long const oldCc, unsigned long const newCc, TimaInt
4148 -void Tima::updateTima(unsigned long const cc) {
4149 - unsigned long const ticks = (cc - lastUpdate_) >> timaClock[tac_ & 3];
4150 +void Tima::updateTima(unsigned const cc) {
4151 + unsigned const ticks = (cc - lastUpdate_) >> timaClock[tac_ & 3];
4152 lastUpdate_ += ticks << timaClock[tac_ & 3];
4154 if (cc >= tmatime_) {
4155 @@ -79,7 +83,7 @@ void Tima::updateTima(unsigned long const cc) {
4156 tima_ = tma_;
4159 - unsigned long tmp = tima_ + ticks;
4160 + unsigned tmp = tima_ + ticks;
4161 while (tmp > 0x100)
4162 tmp -= 0x100 - tma_;
4164 @@ -98,7 +102,7 @@ void Tima::updateTima(unsigned long const cc) {
4165 tima_ = tmp;
4168 -void Tima::setTima(unsigned const data, unsigned long const cc, TimaInterruptRequester timaIrq) {
4169 +void Tima::setTima(unsigned const data, unsigned const cc, TimaInterruptRequester timaIrq) {
4170 if (tac_ & 0x04) {
4171 updateIrq(cc, timaIrq);
4172 updateTima(cc);
4173 @@ -112,7 +116,7 @@ void Tima::setTima(unsigned const data, unsigned long const cc, TimaInterruptReq
4174 tima_ = data;
4177 -void Tima::setTma(unsigned const data, unsigned long const cc, TimaInterruptRequester timaIrq) {
4178 +void Tima::setTma(unsigned const data, unsigned const cc, TimaInterruptRequester timaIrq) {
4179 if (tac_ & 0x04) {
4180 updateIrq(cc, timaIrq);
4181 updateTima(cc);
4182 @@ -121,9 +125,9 @@ void Tima::setTma(unsigned const data, unsigned long const cc, TimaInterruptRequ
4183 tma_ = data;
4186 -void Tima::setTac(unsigned const data, unsigned long const cc, TimaInterruptRequester timaIrq) {
4187 +void Tima::setTac(unsigned const data, unsigned const cc, TimaInterruptRequester timaIrq) {
4188 if (tac_ ^ data) {
4189 - unsigned long nextIrqEventTime = timaIrq.nextIrqEventTime();
4190 + unsigned nextIrqEventTime = timaIrq.nextIrqEventTime();
4192 if (tac_ & 0x04) {
4193 updateIrq(cc, timaIrq);
4194 @@ -153,7 +157,7 @@ void Tima::setTac(unsigned const data, unsigned long const cc, TimaInterruptRequ
4195 tac_ = data;
4198 -unsigned Tima::tima(unsigned long cc) {
4199 +unsigned Tima::tima(unsigned cc) {
4200 if (tac_ & 0x04)
4201 updateTima(cc);
4203 @@ -166,4 +170,13 @@ void Tima::doIrqEvent(TimaInterruptRequester timaIrq) {
4204 + ((256u - tma_) << timaClock[tac_ & 3]));
4207 +void Tima::loadOrSave(loadsave& state)
4209 + state(lastUpdate_);
4210 + state(tmatime_);
4211 + state(tima_);
4212 + state(tma_);
4213 + state(tac_);
4217 diff --git a/libgambatte/src/tima.h b/libgambatte/src/tima.h
4218 index 93afeb9..ce1f51e 100644
4219 --- a/libgambatte/src/tima.h
4220 +++ b/libgambatte/src/tima.h
4221 @@ -19,6 +19,10 @@
4222 #ifndef TIMA_H
4223 #define TIMA_H
4226 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
4227 +// - Make it rerecording-friendly.
4229 #include "interruptrequester.h"
4231 namespace gambatte {
4232 @@ -27,8 +31,8 @@ class TimaInterruptRequester {
4233 public:
4234 explicit TimaInterruptRequester(InterruptRequester &intreq) : intreq_(intreq) {}
4235 void flagIrq() const { intreq_.flagIrq(4); }
4236 - unsigned long nextIrqEventTime() const { return intreq_.eventTime(intevent_tima); }
4237 - void setNextIrqEventTime(unsigned long time) const { intreq_.setEventTime<intevent_tima>(time); }
4238 + unsigned nextIrqEventTime() const { return intreq_.eventTime(intevent_tima); }
4239 + void setNextIrqEventTime(unsigned time) const { intreq_.setEventTime<intevent_tima>(time); }
4241 private:
4242 InterruptRequester &intreq_;
4243 @@ -39,26 +43,26 @@ public:
4244 Tima();
4245 void saveState(SaveState &) const;
4246 void loadState(const SaveState &, TimaInterruptRequester timaIrq);
4247 - void resetCc(unsigned long oldCc, unsigned long newCc, TimaInterruptRequester timaIrq);
4248 - void setTima(unsigned tima, unsigned long cc, TimaInterruptRequester timaIrq);
4249 - void setTma(unsigned tma, unsigned long cc, TimaInterruptRequester timaIrq);
4250 - void setTac(unsigned tac, unsigned long cc, TimaInterruptRequester timaIrq);
4251 - unsigned tima(unsigned long cc);
4252 + void resetCc(unsigned oldCc, unsigned newCc, TimaInterruptRequester timaIrq);
4253 + void setTima(unsigned tima, unsigned cc, TimaInterruptRequester timaIrq);
4254 + void setTma(unsigned tma, unsigned cc, TimaInterruptRequester timaIrq);
4255 + void setTac(unsigned tac, unsigned cc, TimaInterruptRequester timaIrq);
4256 + unsigned tima(unsigned cc);
4257 void doIrqEvent(TimaInterruptRequester timaIrq);
4259 + void updateTima(unsigned cc);
4260 + void loadOrSave(loadsave& state);
4261 private:
4262 - unsigned long lastUpdate_;
4263 - unsigned long tmatime_;
4264 + unsigned lastUpdate_;
4265 + unsigned tmatime_;
4266 unsigned char tima_;
4267 unsigned char tma_;
4268 unsigned char tac_;
4270 - void updateIrq(unsigned long const cc, TimaInterruptRequester timaIrq) {
4271 + void updateIrq(unsigned const cc, TimaInterruptRequester timaIrq) {
4272 while (cc >= timaIrq.nextIrqEventTime())
4273 doIrqEvent(timaIrq);
4276 - void updateTima(unsigned long cc);
4280 diff --git a/libgambatte/src/video.cpp b/libgambatte/src/video.cpp
4281 index 3205e90..5cb4b08 100644
4282 --- a/libgambatte/src/video.cpp
4283 +++ b/libgambatte/src/video.cpp
4284 @@ -21,19 +21,23 @@
4285 #include <algorithm>
4286 #include <cstring>
4289 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
4290 +// - Make it rerecording-friendly.
4292 namespace gambatte {
4294 -void LCD::setDmgPalette(unsigned long palette[], unsigned long const dmgColors[], unsigned data) {
4295 +void LCD::setDmgPalette(uint_least32_t palette[], uint_least32_t const dmgColors[], unsigned data) {
4296 palette[0] = dmgColors[data & 3];
4297 palette[1] = dmgColors[data >> 2 & 3];
4298 palette[2] = dmgColors[data >> 4 & 3];
4299 palette[3] = dmgColors[data >> 6 & 3];
4302 -static unsigned long gbcToRgb32(unsigned const bgr15) {
4303 - unsigned long const r = bgr15 & 0x1F;
4304 - unsigned long const g = bgr15 >> 5 & 0x1F;
4305 - unsigned long const b = bgr15 >> 10 & 0x1F;
4306 +static uint_least32_t gbcToRgb32(unsigned const bgr15) {
4307 + uint_least32_t const r = bgr15 & 0x1F;
4308 + uint_least32_t const g = bgr15 >> 5 & 0x1F;
4309 + uint_least32_t const b = bgr15 >> 10 & 0x1F;
4311 return ((r * 13 + g * 2 + b) >> 1) << 16
4312 | (g * 3 + b) << 9
4313 @@ -85,7 +89,6 @@ LCD::LCD(unsigned char const *oamram, unsigned char const *vram,
4314 dmgColorsRgb32_[i] = (3 - (i & 3)) * 85 * 0x010101ul;
4316 reset(oamram, vram, false);
4317 - setVideoBuffer(0, 160);
4320 void LCD::reset(unsigned char const *oamram, unsigned char const *vram, bool cgb) {
4321 @@ -94,8 +97,8 @@ void LCD::reset(unsigned char const *oamram, unsigned char const *vram, bool cgb
4322 refreshPalettes();
4325 -static unsigned long mode2IrqSchedule(unsigned const statReg,
4326 - LyCounter const &lyCounter, unsigned long const cc) {
4327 +static unsigned mode2IrqSchedule(unsigned const statReg,
4328 + LyCounter const &lyCounter, unsigned const cc) {
4329 if (!(statReg & lcdstat_m2irqen))
4330 return disabled_time;
4332 @@ -113,16 +116,16 @@ static unsigned long mode2IrqSchedule(unsigned const statReg,
4333 return cc + next;
4336 -static unsigned long m0IrqTimeFromXpos166Time(unsigned long xpos166Time, bool cgb, bool ds) {
4337 +static unsigned m0IrqTimeFromXpos166Time(unsigned xpos166Time, bool cgb, bool ds) {
4338 return xpos166Time + cgb - ds;
4341 -static unsigned long hdmaTimeFromM0Time(unsigned long m0Time, bool ds) {
4342 +static unsigned hdmaTimeFromM0Time(unsigned m0Time, bool ds) {
4343 return m0Time + 1 - ds;
4346 -static unsigned long nextHdmaTime(unsigned long lastM0Time,
4347 - unsigned long nextM0Time, unsigned long cc, bool ds) {
4348 +static unsigned nextHdmaTime(unsigned lastM0Time,
4349 + unsigned nextM0Time, unsigned cc, bool ds) {
4350 return cc < hdmaTimeFromM0Time(lastM0Time, ds)
4351 ? hdmaTimeFromM0Time(lastM0Time, ds)
4352 : hdmaTimeFromM0Time(nextM0Time, ds);
4353 @@ -160,11 +163,11 @@ void LCD::loadState(SaveState const &state, unsigned char const *const oamram) {
4354 eventTimes_.setm<memevent_oneshot_statirq>(
4355 state.ppu.pendingLcdstatIrq
4356 ? ppu_.now() + 1
4357 - : static_cast<unsigned long>(disabled_time));
4358 + : static_cast<unsigned>(disabled_time));
4359 eventTimes_.setm<memevent_oneshot_updatewy2>(
4360 state.ppu.oldWy != state.mem.ioamhram.get()[0x14A]
4361 ? ppu_.now() + 1
4362 - : static_cast<unsigned long>(disabled_time));
4363 + : static_cast<unsigned>(disabled_time));
4364 eventTimes_.set<event_ly>(ppu_.lyCounter().time());
4365 eventTimes_.setm<memevent_spritemap>(
4366 SpriteMapper::schedule(ppu_.lyCounter(), ppu_.now()));
4367 @@ -175,11 +178,11 @@ void LCD::loadState(SaveState const &state, unsigned char const *const oamram) {
4368 mode2IrqSchedule(statReg_, ppu_.lyCounter(), ppu_.now()));
4369 eventTimes_.setm<memevent_m0irq>(statReg_ & lcdstat_m0irqen
4370 ? ppu_.now() + state.ppu.nextM0Irq
4371 - : static_cast<unsigned long>(disabled_time));
4372 + : static_cast<unsigned>(disabled_time));
4373 eventTimes_.setm<memevent_hdma>(state.mem.hdmaTransfer
4374 ? nextHdmaTime(ppu_.lastM0Time(), nextM0Time_.predictedNextM0Time(),
4375 ppu_.now(), isDoubleSpeed())
4376 - : static_cast<unsigned long>(disabled_time));
4377 + : static_cast<unsigned>(disabled_time));
4378 } else for (int i = 0; i < num_memevents; ++i)
4379 eventTimes_.set(MemEvent(i), disabled_time);
4381 @@ -230,7 +233,7 @@ struct Blend {
4384 template<typename T>
4385 -static void clear(T *buf, unsigned long color, std::ptrdiff_t dpitch) {
4386 +static void clear(T *buf, uint_least32_t color, std::ptrdiff_t dpitch) {
4387 unsigned lines = 144;
4389 while (lines--) {
4390 @@ -241,11 +244,11 @@ static void clear(T *buf, unsigned long color, std::ptrdiff_t dpitch) {
4394 -void LCD::updateScreen(bool const blanklcd, unsigned long const cycleCounter) {
4395 +void LCD::updateScreen(bool const blanklcd, unsigned const cycleCounter, uint_least32_t* vbuffer, unsigned vpitch) {
4396 update(cycleCounter);
4398 if (blanklcd && ppu_.frameBuf().fb()) {
4399 - unsigned long color = ppu_.cgb() ? gbcToRgb32(0xFFFF) : dmgColorsRgb32_[0];
4400 + uint_least32_t color = ppu_.cgb() ? gbcToRgb32(0xFFFF) : dmgColorsRgb32_[0];
4401 clear(ppu_.frameBuf().fb(), color, ppu_.frameBuf().pitch());
4404 @@ -268,14 +271,15 @@ void LCD::updateScreen(bool const blanklcd, unsigned long const cycleCounter) {
4405 } else
4406 osdElement_.reset();
4408 + ppu_.frameBuf().blit(vbuffer, vpitch);
4411 -void LCD::resetCc(unsigned long const oldCc, unsigned long const newCc) {
4412 +void LCD::resetCc(unsigned const oldCc, unsigned const newCc) {
4413 update(oldCc);
4414 ppu_.resetCc(oldCc, newCc);
4416 if (ppu_.lcdc() & lcdc_en) {
4417 - unsigned long const dec = oldCc - newCc;
4418 + unsigned const dec = oldCc - newCc;
4420 nextM0Time_.invalidatePredictedNextM0Time();
4421 lycIrq_.reschedule(ppu_.lyCounter(), newCc);
4422 @@ -289,7 +293,7 @@ void LCD::resetCc(unsigned long const oldCc, unsigned long const newCc) {
4426 -void LCD::speedChange(unsigned long const cc) {
4427 +void LCD::speedChange(unsigned const cc) {
4428 update(cc);
4429 ppu_.speedChange(cc);
4431 @@ -316,14 +320,14 @@ void LCD::speedChange(unsigned long const cc) {
4435 -static unsigned long m0TimeOfCurrentLine(
4436 - unsigned long nextLyTime,
4437 - unsigned long lastM0Time,
4438 - unsigned long nextM0Time) {
4439 +static unsigned m0TimeOfCurrentLine(
4440 + unsigned nextLyTime,
4441 + unsigned lastM0Time,
4442 + unsigned nextM0Time) {
4443 return nextM0Time < nextLyTime ? nextM0Time : lastM0Time;
4446 -unsigned long LCD::m0TimeOfCurrentLine(unsigned long const cc) {
4447 +unsigned LCD::m0TimeOfCurrentLine(unsigned const cc) {
4448 if (cc >= nextM0Time_.predictedNextM0Time()) {
4449 update(cc);
4450 nextM0Time_.predictNextM0Time(ppu_);
4451 @@ -334,20 +338,20 @@ unsigned long LCD::m0TimeOfCurrentLine(unsigned long const cc) {
4454 static bool isHdmaPeriod(LyCounter const &lyCounter,
4455 - unsigned long m0TimeOfCurrentLy, unsigned long cc) {
4456 + unsigned m0TimeOfCurrentLy, unsigned cc) {
4457 int timeToNextLy = lyCounter.time() - cc;
4458 return lyCounter.ly() < 144 && timeToNextLy > 4
4459 && cc >= hdmaTimeFromM0Time(m0TimeOfCurrentLy, lyCounter.isDoubleSpeed());
4462 -void LCD::enableHdma(unsigned long const cycleCounter) {
4463 +void LCD::enableHdma(unsigned const cycleCounter) {
4464 if (cycleCounter >= nextM0Time_.predictedNextM0Time()) {
4465 update(cycleCounter);
4466 nextM0Time_.predictNextM0Time(ppu_);
4467 } else if (cycleCounter >= eventTimes_.nextEventTime())
4468 update(cycleCounter);
4470 - unsigned long const m0TimeCurLy =
4471 + unsigned const m0TimeCurLy =
4472 gambatte::m0TimeOfCurrentLine(ppu_.lyCounter().time(),
4473 ppu_.lastM0Time(),
4474 nextM0Time_.predictedNextM0Time());
4475 @@ -359,14 +363,14 @@ void LCD::enableHdma(unsigned long const cycleCounter) {
4476 cycleCounter, isDoubleSpeed()));
4479 -void LCD::disableHdma(unsigned long const cycleCounter) {
4480 +void LCD::disableHdma(unsigned const cycleCounter) {
4481 if (cycleCounter >= eventTimes_.nextEventTime())
4482 update(cycleCounter);
4484 eventTimes_.setm<memevent_hdma>(disabled_time);
4487 -bool LCD::vramAccessible(unsigned long const cc) {
4488 +bool LCD::vramAccessible(unsigned const cc) {
4489 if (cc >= eventTimes_.nextEventTime())
4490 update(cc);
4492 @@ -376,7 +380,7 @@ bool LCD::vramAccessible(unsigned long const cc) {
4493 || cc + isDoubleSpeed() - ppu_.cgb() + 2 >= m0TimeOfCurrentLine(cc);
4496 -bool LCD::cgbpAccessible(unsigned long const cc) {
4497 +bool LCD::cgbpAccessible(unsigned const cc) {
4498 if (cc >= eventTimes_.nextEventTime())
4499 update(cc);
4501 @@ -387,27 +391,27 @@ bool LCD::cgbpAccessible(unsigned long const cc) {
4504 static void doCgbColorChange(unsigned char *pdata,
4505 - unsigned long *palette, unsigned index, unsigned data) {
4506 + uint_least32_t *palette, unsigned index, unsigned data) {
4507 pdata[index] = data;
4508 index >>= 1;
4509 palette[index] = gbcToRgb32(pdata[index * 2] | pdata[index * 2 + 1] << 8);
4512 -void LCD::doCgbBgColorChange(unsigned index, unsigned data, unsigned long cc) {
4513 +void LCD::doCgbBgColorChange(unsigned index, unsigned data, unsigned cc) {
4514 if (cgbpAccessible(cc)) {
4515 update(cc);
4516 doCgbColorChange(bgpData_, ppu_.bgPalette(), index, data);
4520 -void LCD::doCgbSpColorChange(unsigned index, unsigned data, unsigned long cc) {
4521 +void LCD::doCgbSpColorChange(unsigned index, unsigned data, unsigned cc) {
4522 if (cgbpAccessible(cc)) {
4523 update(cc);
4524 doCgbColorChange(objpData_, ppu_.spPalette(), index, data);
4528 -bool LCD::oamReadable(unsigned long const cc) {
4529 +bool LCD::oamReadable(unsigned const cc) {
4530 if (!(ppu_.lcdc() & lcdc_en) || ppu_.inactivePeriodAfterDisplayEnable(cc))
4531 return true;
4533 @@ -421,7 +425,7 @@ bool LCD::oamReadable(unsigned long const cc) {
4534 || cc + isDoubleSpeed() - ppu_.cgb() + 2 >= m0TimeOfCurrentLine(cc);
4537 -bool LCD::oamWritable(unsigned long const cc) {
4538 +bool LCD::oamWritable(unsigned const cc) {
4539 if (!(ppu_.lcdc() & lcdc_en) || ppu_.inactivePeriodAfterDisplayEnable(cc))
4540 return true;
4542 @@ -442,7 +446,7 @@ void LCD::mode3CyclesChange() {
4543 if (eventTimes_(memevent_m0irq) != disabled_time
4544 && eventTimes_(memevent_m0irq)
4545 > m0IrqTimeFromXpos166Time(ppu_.now(), ppu_.cgb(), ds)) {
4546 - unsigned long t = m0IrqTimeFromXpos166Time(ppu_.predictedNextXposTime(166),
4547 + unsigned t = m0IrqTimeFromXpos166Time(ppu_.predictedNextXposTime(166),
4548 ppu_.cgb(), ds);
4549 eventTimes_.setm<memevent_m0irq>(t);
4551 @@ -455,13 +459,13 @@ void LCD::mode3CyclesChange() {
4555 -void LCD::wxChange(unsigned newValue, unsigned long cycleCounter) {
4556 +void LCD::wxChange(unsigned newValue, unsigned cycleCounter) {
4557 update(cycleCounter + isDoubleSpeed() + 1);
4558 ppu_.setWx(newValue);
4559 mode3CyclesChange();
4562 -void LCD::wyChange(unsigned const newValue, unsigned long const cc) {
4563 +void LCD::wyChange(unsigned const newValue, unsigned const cc) {
4564 update(cc + 1);
4565 ppu_.setWy(newValue);
4567 @@ -479,18 +483,18 @@ void LCD::wyChange(unsigned const newValue, unsigned long const cc) {
4571 -void LCD::scxChange(unsigned newScx, unsigned long cycleCounter) {
4572 +void LCD::scxChange(unsigned newScx, unsigned cycleCounter) {
4573 update(cycleCounter + ppu_.cgb() + isDoubleSpeed());
4574 ppu_.setScx(newScx);
4575 mode3CyclesChange();
4578 -void LCD::scyChange(unsigned newValue, unsigned long cycleCounter) {
4579 +void LCD::scyChange(unsigned newValue, unsigned cycleCounter) {
4580 update(cycleCounter + ppu_.cgb() + isDoubleSpeed());
4581 ppu_.setScy(newValue);
4584 -void LCD::oamChange(unsigned long cc) {
4585 +void LCD::oamChange(unsigned cc) {
4586 if (ppu_.lcdc() & lcdc_en) {
4587 update(cc);
4588 ppu_.oamChange(cc);
4589 @@ -498,7 +502,7 @@ void LCD::oamChange(unsigned long cc) {
4593 -void LCD::oamChange(unsigned char const *oamram, unsigned long cc) {
4594 +void LCD::oamChange(unsigned char const *oamram, unsigned cc) {
4595 update(cc);
4596 ppu_.oamChange(oamram, cc);
4598 @@ -506,7 +510,7 @@ void LCD::oamChange(unsigned char const *oamram, unsigned long cc) {
4599 eventTimes_.setm<memevent_spritemap>(SpriteMapper::schedule(ppu_.lyCounter(), cc));
4602 -void LCD::lcdcChange(unsigned const data, unsigned long const cc) {
4603 +void LCD::lcdcChange(unsigned const data, unsigned const cc) {
4604 unsigned const oldLcdc = ppu_.lcdc();
4605 update(cc);
4607 @@ -547,7 +551,7 @@ void LCD::lcdcChange(unsigned const data, unsigned long const cc) {
4608 | (data & (lcdc_tdsel | lcdc_obj2x)), cc);
4610 if ((oldLcdc ^ data) & lcdc_obj2x) {
4611 - unsigned long t = SpriteMapper::schedule(ppu_.lyCounter(), cc);
4612 + unsigned t = SpriteMapper::schedule(ppu_.lyCounter(), cc);
4613 eventTimes_.setm<memevent_spritemap>(t);
4616 @@ -560,7 +564,7 @@ void LCD::lcdcChange(unsigned const data, unsigned long const cc) {
4617 ppu_.setLcdc(data, cc);
4619 if ((oldLcdc ^ data) & lcdc_obj2x) {
4620 - unsigned long t = SpriteMapper::schedule(ppu_.lyCounter(), cc);
4621 + unsigned t = SpriteMapper::schedule(ppu_.lyCounter(), cc);
4622 eventTimes_.setm<memevent_spritemap>(t);
4625 @@ -578,7 +582,7 @@ struct LyCnt {
4626 LyCnt(unsigned ly, int timeToNextLy) : ly(ly), timeToNextLy(timeToNextLy) {}
4629 -static LyCnt const getLycCmpLy(LyCounter const &lyCounter, unsigned long cc) {
4630 +static LyCnt const getLycCmpLy(LyCounter const &lyCounter, unsigned cc) {
4631 unsigned ly = lyCounter.ly();
4632 int timeToNextLy = lyCounter.time() - cc;
4634 @@ -596,7 +600,7 @@ static LyCnt const getLycCmpLy(LyCounter const &lyCounter, unsigned long cc) {
4636 } // anon ns
4638 -inline bool LCD::statChangeTriggersStatIrqDmg(unsigned const old, unsigned long const cc) {
4639 +inline bool LCD::statChangeTriggersStatIrqDmg(unsigned const old, unsigned const cc) {
4640 LyCnt const lycCmp = getLycCmpLy(ppu_.lyCounter(), cc);
4642 if (ppu_.lyCounter().ly() < 144) {
4643 @@ -624,7 +628,7 @@ static bool statChangeTriggersM2IrqCgb(unsigned const old,
4646 inline bool LCD::statChangeTriggersM0LycOrM1StatIrqCgb(
4647 - unsigned const old, unsigned const data, unsigned long const cc) {
4648 + unsigned const old, unsigned const data, unsigned const cc) {
4649 unsigned const ly = ppu_.lyCounter().ly();
4650 int const timeToNextLy = ppu_.lyCounter().time() - cc;
4651 LyCnt const lycCmp = getLycCmpLy(ppu_.lyCounter(), cc);
4652 @@ -652,7 +656,7 @@ inline bool LCD::statChangeTriggersM0LycOrM1StatIrqCgb(
4655 inline bool LCD::statChangeTriggersStatIrqCgb(
4656 - unsigned const old, unsigned const data, unsigned long const cc) {
4657 + unsigned const old, unsigned const data, unsigned const cc) {
4658 if (!(data & ~old & ( lcdstat_lycirqen
4659 | lcdstat_m2irqen
4660 | lcdstat_m1irqen
4661 @@ -666,13 +670,13 @@ inline bool LCD::statChangeTriggersStatIrqCgb(
4662 || statChangeTriggersM2IrqCgb(old, data, ly, timeToNextLy);
4665 -inline bool LCD::statChangeTriggersStatIrq(unsigned old, unsigned data, unsigned long cc) {
4666 +inline bool LCD::statChangeTriggersStatIrq(unsigned old, unsigned data, unsigned cc) {
4667 return ppu_.cgb()
4668 ? statChangeTriggersStatIrqCgb(old, data, cc)
4669 : statChangeTriggersStatIrqDmg(old, cc);
4672 -void LCD::lcdstatChange(unsigned const data, unsigned long const cc) {
4673 +void LCD::lcdstatChange(unsigned const data, unsigned const cc) {
4674 if (cc >= eventTimes_.nextEventTime())
4675 update(cc);
4677 @@ -706,7 +710,7 @@ void LCD::lcdstatChange(unsigned const data, unsigned long const cc) {
4679 static unsigned incLy(unsigned ly) { return ly == 153 ? 0 : ly + 1; }
4681 -inline bool LCD::lycRegChangeStatTriggerBlockedByM0OrM1Irq(unsigned long const cc) {
4682 +inline bool LCD::lycRegChangeStatTriggerBlockedByM0OrM1Irq(unsigned const cc) {
4683 int const timeToNextLy = ppu_.lyCounter().time() - cc;
4684 if (ppu_.lyCounter().ly() < 144) {
4685 return (statReg_ & lcdstat_m0irqen)
4686 @@ -721,7 +725,7 @@ inline bool LCD::lycRegChangeStatTriggerBlockedByM0OrM1Irq(unsigned long const c
4689 bool LCD::lycRegChangeTriggersStatIrq(
4690 - unsigned const old, unsigned const data, unsigned long const cc) {
4691 + unsigned const old, unsigned const data, unsigned const cc) {
4692 if (!(statReg_ & lcdstat_lycirqen) || data >= 154
4693 || lycRegChangeStatTriggerBlockedByM0OrM1Irq(cc)) {
4694 return false;
4695 @@ -739,7 +743,7 @@ bool LCD::lycRegChangeTriggersStatIrq(
4696 return data == lycCmp.ly;
4699 -void LCD::lycRegChange(unsigned const data, unsigned long const cc) {
4700 +void LCD::lycRegChange(unsigned const data, unsigned const cc) {
4701 unsigned const old = lycIrq_.lycReg();
4702 if (data == old)
4703 return;
4704 @@ -762,7 +766,7 @@ void LCD::lycRegChange(unsigned const data, unsigned long const cc) {
4708 -unsigned LCD::getStat(unsigned const lycReg, unsigned long const cc) {
4709 +unsigned LCD::getStat(unsigned const lycReg, unsigned const cc) {
4710 unsigned stat = 0;
4712 if (ppu_.lcdc() & lcdc_en) {
4713 @@ -815,7 +819,7 @@ inline void LCD::doMode2IrqEvent() {
4714 m2IrqStatReg_ = statReg_;
4716 if (!(statReg_ & lcdstat_m0irqen)) {
4717 - unsigned long nextTime = eventTimes_(memevent_m2irq) + ppu_.lyCounter().lineTime();
4718 + unsigned nextTime = eventTimes_(memevent_m2irq) + ppu_.lyCounter().lineTime();
4719 if (ly == 0) {
4720 nextTime -= 4;
4721 } else if (ly == 143)
4722 @@ -878,7 +882,7 @@ inline void LCD::event() {
4723 eventTimes_.setm<memevent_m0irq>(statReg_ & lcdstat_m0irqen
4724 ? m0IrqTimeFromXpos166Time(ppu_.predictedNextXposTime(166),
4725 ppu_.cgb(), isDoubleSpeed())
4726 - : static_cast<unsigned long>(disabled_time));
4727 + : static_cast<unsigned>(disabled_time));
4728 break;
4730 case memevent_oneshot_statirq:
4731 @@ -902,7 +906,7 @@ inline void LCD::event() {
4735 -void LCD::update(unsigned long const cycleCounter) {
4736 +void LCD::update(unsigned const cycleCounter) {
4737 if (!(ppu_.lcdc() & lcdc_en))
4738 return;
4740 @@ -914,11 +918,11 @@ void LCD::update(unsigned long const cycleCounter) {
4741 ppu_.update(cycleCounter);
4744 -void LCD::setVideoBuffer(uint_least32_t *videoBuf, std::ptrdiff_t pitch) {
4745 - ppu_.setFrameBuf(videoBuf, pitch);
4746 +void LCD::setDmgPaletteColor(unsigned index, uint_least32_t rgb32) {
4747 + dmgColorsRgb32_[index] = rgb32;
4750 -void LCD::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32) {
4751 +void LCD::setDmgPaletteColor(unsigned palNum, unsigned colorNum, uint_least32_t rgb32) {
4752 if (palNum > 2 || colorNum > 3)
4753 return;
4755 @@ -926,4 +930,18 @@ void LCD::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long r
4756 refreshPalettes();
4759 +void LCD::loadOrSave(loadsave& state) {
4760 + ppu_.loadOrSave(state);
4761 + state(dmgColorsRgb32_, 12);
4762 + state(bgpData_, 64);
4763 + state(objpData_, 64);
4764 + eventTimes_.loadOrSave(state);
4765 + m0Irq_.loadOrSave(state);
4766 + lycIrq_.loadOrSave(state);
4767 + nextM0Time_.loadOrSave(state);
4768 + state(statReg_);
4769 + state(m2IrqStatReg_);
4770 + state(m1IrqStatReg_);
4774 diff --git a/libgambatte/src/video.h b/libgambatte/src/video.h
4775 index dbef702..105e761 100644
4776 --- a/libgambatte/src/video.h
4777 +++ b/libgambatte/src/video.h
4778 @@ -19,6 +19,13 @@
4779 #ifndef VIDEO_H
4780 #define VIDEO_H
4783 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
4784 +// - Make it rerecording-friendly.
4786 +#include "video/ppu.h"
4787 +#include "video/lyc_irq.h"
4788 +#include "video/next_m0_time.h"
4789 #include "interruptrequester.h"
4790 #include "minkeeper.h"
4791 #include "osd_element.h"
4792 @@ -39,7 +46,7 @@ public:
4794 void flagHdmaReq() const { gambatte::flagHdmaReq(intreq_); }
4795 void flagIrq(unsigned bit) const { intreq_.flagIrq(bit); }
4796 - void setNextEventTime(unsigned long time) const { intreq_.setEventTime<intevent_video>(time); }
4797 + void setNextEventTime(unsigned time) const { intreq_.setEventTime<intevent_video>(time); }
4799 private:
4800 InterruptRequester &intreq_;
4801 @@ -52,63 +59,63 @@ public:
4802 void reset(unsigned char const *oamram, unsigned char const *vram, bool cgb);
4803 void setStatePtrs(SaveState &state);
4804 void saveState(SaveState &state) const;
4805 + void loadOrSave(loadsave& state);
4806 void loadState(SaveState const &state, unsigned char const *oamram);
4807 - void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32);
4808 - void setVideoBuffer(uint_least32_t *videoBuf, std::ptrdiff_t pitch);
4809 + void setDmgPaletteColor(unsigned palNum, unsigned colorNum, uint_least32_t rgb32);
4810 void setOsdElement(transfer_ptr<OsdElement> osdElement) { osdElement_ = osdElement; }
4812 - void dmgBgPaletteChange(unsigned data, unsigned long cycleCounter) {
4813 + void dmgBgPaletteChange(unsigned data, unsigned cycleCounter) {
4814 update(cycleCounter);
4815 bgpData_[0] = data;
4816 setDmgPalette(ppu_.bgPalette(), dmgColorsRgb32_, data);
4819 - void dmgSpPalette1Change(unsigned data, unsigned long cycleCounter) {
4820 + void dmgSpPalette1Change(unsigned data, unsigned cycleCounter) {
4821 update(cycleCounter);
4822 objpData_[0] = data;
4823 setDmgPalette(ppu_.spPalette(), dmgColorsRgb32_ + 4, data);
4826 - void dmgSpPalette2Change(unsigned data, unsigned long cycleCounter) {
4827 + void dmgSpPalette2Change(unsigned data, unsigned cycleCounter) {
4828 update(cycleCounter);
4829 objpData_[1] = data;
4830 setDmgPalette(ppu_.spPalette() + 4, dmgColorsRgb32_ + 8, data);
4833 - void cgbBgColorChange(unsigned index, unsigned data, unsigned long cycleCounter) {
4834 + void cgbBgColorChange(unsigned index, unsigned data, unsigned cycleCounter) {
4835 if (bgpData_[index] != data)
4836 doCgbBgColorChange(index, data, cycleCounter);
4839 - void cgbSpColorChange(unsigned index, unsigned data, unsigned long cycleCounter) {
4840 + void cgbSpColorChange(unsigned index, unsigned data, unsigned cycleCounter) {
4841 if (objpData_[index] != data)
4842 doCgbSpColorChange(index, data, cycleCounter);
4845 - unsigned cgbBgColorRead(unsigned index, unsigned long cycleCounter) {
4846 + unsigned cgbBgColorRead(unsigned index, unsigned cycleCounter) {
4847 return ppu_.cgb() & cgbpAccessible(cycleCounter) ? bgpData_[index] : 0xFF;
4850 - unsigned cgbSpColorRead(unsigned index, unsigned long cycleCounter) {
4851 + unsigned cgbSpColorRead(unsigned index, unsigned cycleCounter) {
4852 return ppu_.cgb() & cgbpAccessible(cycleCounter) ? objpData_[index] : 0xFF;
4855 - void updateScreen(bool blanklcd, unsigned long cc);
4856 - void resetCc(unsigned long oldCC, unsigned long newCc);
4857 - void speedChange(unsigned long cycleCounter);
4858 - bool vramAccessible(unsigned long cycleCounter);
4859 - bool oamReadable(unsigned long cycleCounter);
4860 - bool oamWritable(unsigned long cycleCounter);
4861 - void wxChange(unsigned newValue, unsigned long cycleCounter);
4862 - void wyChange(unsigned newValue, unsigned long cycleCounter);
4863 - void oamChange(unsigned long cycleCounter);
4864 - void oamChange(const unsigned char *oamram, unsigned long cycleCounter);
4865 - void scxChange(unsigned newScx, unsigned long cycleCounter);
4866 - void scyChange(unsigned newValue, unsigned long cycleCounter);
4867 - void vramChange(unsigned long cycleCounter) { update(cycleCounter); }
4868 - unsigned getStat(unsigned lycReg, unsigned long cycleCounter);
4870 - unsigned getLyReg(unsigned long const cc) {
4871 + void updateScreen(bool blanklcd, unsigned cc, uint_least32_t* vbuffer, unsigned vpitch);
4872 + void resetCc(unsigned oldCC, unsigned newCc);
4873 + void speedChange(unsigned cycleCounter);
4874 + bool vramAccessible(unsigned cycleCounter);
4875 + bool oamReadable(unsigned cycleCounter);
4876 + bool oamWritable(unsigned cycleCounter);
4877 + void wxChange(unsigned newValue, unsigned cycleCounter);
4878 + void wyChange(unsigned newValue, unsigned cycleCounter);
4879 + void oamChange(unsigned cycleCounter);
4880 + void oamChange(const unsigned char *oamram, unsigned cycleCounter);
4881 + void scxChange(unsigned newScx, unsigned cycleCounter);
4882 + void scyChange(unsigned newValue, unsigned cycleCounter);
4883 + void vramChange(unsigned cycleCounter) { update(cycleCounter); }
4884 + unsigned getStat(unsigned lycReg, unsigned cycleCounter);
4886 + unsigned getLyReg(unsigned const cc) {
4887 unsigned lyReg = 0;
4889 if (ppu_.lcdc() & lcdc_en) {
4890 @@ -130,14 +137,14 @@ public:
4891 return lyReg;
4894 - unsigned long nextMode1IrqTime() const { return eventTimes_(memevent_m1irq); }
4895 - void lcdcChange(unsigned data, unsigned long cycleCounter);
4896 - void lcdstatChange(unsigned data, unsigned long cycleCounter);
4897 - void lycRegChange(unsigned data, unsigned long cycleCounter);
4898 - void enableHdma(unsigned long cycleCounter);
4899 - void disableHdma(unsigned long cycleCounter);
4900 + unsigned nextMode1IrqTime() const { return eventTimes_(memevent_m1irq); }
4901 + void lcdcChange(unsigned data, unsigned cycleCounter);
4902 + void lcdstatChange(unsigned data, unsigned cycleCounter);
4903 + void lycRegChange(unsigned data, unsigned cycleCounter);
4904 + void enableHdma(unsigned cycleCounter);
4905 + void disableHdma(unsigned cycleCounter);
4906 bool hdmaIsEnabled() const { return eventTimes_(memevent_hdma) != disabled_time; }
4907 - void update(unsigned long cycleCounter);
4908 + void update(unsigned cycleCounter);
4909 bool isCgb() const { return ppu_.cgb(); }
4910 bool isDoubleSpeed() const { return ppu_.lyCounter().isDoubleSpeed(); }
4912 @@ -165,36 +172,41 @@ private:
4915 Event nextEvent() const { return static_cast<Event>(eventMin_.min()); }
4916 - unsigned long nextEventTime() const { return eventMin_.minValue(); }
4917 - unsigned long operator()(Event e) const { return eventMin_.value(e); }
4918 - template<Event e> void set(unsigned long time) { eventMin_.setValue<e>(time); }
4919 - void set(Event e, unsigned long time) { eventMin_.setValue(e, time); }
4920 + unsigned nextEventTime() const { return eventMin_.minValue(); }
4921 + unsigned operator()(Event e) const { return eventMin_.value(e); }
4922 + template<Event e> void set(unsigned time) { eventMin_.setValue<e>(time); }
4923 + void set(Event e, unsigned time) { eventMin_.setValue(e, time); }
4925 MemEvent nextMemEvent() const { return static_cast<MemEvent>(memEventMin_.min()); }
4926 - unsigned long nextMemEventTime() const { return memEventMin_.minValue(); }
4927 - unsigned long operator()(MemEvent e) const { return memEventMin_.value(e); }
4928 + unsigned nextMemEventTime() const { return memEventMin_.minValue(); }
4929 + unsigned operator()(MemEvent e) const { return memEventMin_.value(e); }
4931 template<MemEvent e>
4932 - void setm(unsigned long time) { memEventMin_.setValue<e>(time); setMemEvent(); }
4933 - void set(MemEvent e, unsigned long time) { memEventMin_.setValue(e, time); setMemEvent(); }
4934 + void setm(unsigned time) { memEventMin_.setValue<e>(time); setMemEvent(); }
4935 + void set(MemEvent e, unsigned time) { memEventMin_.setValue(e, time); setMemEvent(); }
4937 void flagIrq(unsigned bit) { memEventRequester_.flagIrq(bit); }
4938 void flagHdmaReq() { memEventRequester_.flagHdmaReq(); }
4940 + void loadOrSave(loadsave& state) {
4941 + eventMin_.loadOrSave(state);
4942 + memEventMin_.loadOrSave(state);
4944 private:
4945 MinKeeper<num_events> eventMin_;
4946 MinKeeper<num_memevents> memEventMin_;
4947 VideoInterruptRequester memEventRequester_;
4949 void setMemEvent() {
4950 - unsigned long nmet = nextMemEventTime();
4951 + unsigned nmet = nextMemEventTime();
4952 eventMin_.setValue<event_mem>(nmet);
4953 memEventRequester_.setNextEventTime(nmet);
4958 PPU ppu_;
4959 - unsigned long dmgColorsRgb32_[3 * 4];
4960 + uint_least32_t dmgColorsRgb32_[3 * 4];
4961 unsigned char bgpData_[8 * 8];
4962 unsigned char objpData_[8 * 8];
4963 EventTimes eventTimes_;
4964 @@ -206,24 +218,25 @@ private:
4965 unsigned char m2IrqStatReg_;
4966 unsigned char m1IrqStatReg_;
4968 - static void setDmgPalette(unsigned long palette[],
4969 - unsigned long const dmgColors[],
4970 + static void setDmgPalette(uint_least32_t palette[],
4971 + uint_least32_t const dmgColors[],
4972 unsigned data);
4973 + void setDmgPaletteColor(unsigned index, uint_least32_t rgb32);
4974 void refreshPalettes();
4975 void setDBuffer();
4976 void doMode2IrqEvent();
4977 void event();
4978 - unsigned long m0TimeOfCurrentLine(unsigned long cc);
4979 - bool cgbpAccessible(unsigned long cycleCounter);
4980 - bool lycRegChangeStatTriggerBlockedByM0OrM1Irq(unsigned long cc);
4981 - bool lycRegChangeTriggersStatIrq(unsigned old, unsigned data, unsigned long cc);
4982 - bool statChangeTriggersM0LycOrM1StatIrqCgb(unsigned old, unsigned data, unsigned long cc);
4983 - bool statChangeTriggersStatIrqCgb(unsigned old, unsigned data, unsigned long cc);
4984 - bool statChangeTriggersStatIrqDmg(unsigned old, unsigned long cc);
4985 - bool statChangeTriggersStatIrq(unsigned old, unsigned data, unsigned long cc);
4986 + unsigned m0TimeOfCurrentLine(unsigned cc);
4987 + bool cgbpAccessible(unsigned cycleCounter);
4988 + bool lycRegChangeStatTriggerBlockedByM0OrM1Irq(unsigned cc);
4989 + bool lycRegChangeTriggersStatIrq(unsigned old, unsigned data, unsigned cc);
4990 + bool statChangeTriggersM0LycOrM1StatIrqCgb(unsigned old, unsigned data, unsigned cc);
4991 + bool statChangeTriggersStatIrqCgb(unsigned old, unsigned data, unsigned cc);
4992 + bool statChangeTriggersStatIrqDmg(unsigned old, unsigned cc);
4993 + bool statChangeTriggersStatIrq(unsigned old, unsigned data, unsigned cc);
4994 void mode3CyclesChange();
4995 - void doCgbBgColorChange(unsigned index, unsigned data, unsigned long cycleCounter);
4996 - void doCgbSpColorChange(unsigned index, unsigned data, unsigned long cycleCounter);
4997 + void doCgbBgColorChange(unsigned index, unsigned data, unsigned cycleCounter);
4998 + void doCgbSpColorChange(unsigned index, unsigned data, unsigned cycleCounter);
5002 diff --git a/libgambatte/src/video/ly_counter.cpp b/libgambatte/src/video/ly_counter.cpp
5003 index 0eb2961..d930d66 100644
5004 --- a/libgambatte/src/video/ly_counter.cpp
5005 +++ b/libgambatte/src/video/ly_counter.cpp
5006 @@ -19,6 +19,10 @@
5007 #include "ly_counter.h"
5008 #include "../savestate.h"
5011 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
5012 +// - Make it rerecording-friendly.
5014 namespace gambatte {
5016 LyCounter::LyCounter()
5017 @@ -39,23 +43,23 @@ void LyCounter::doEvent() {
5018 time_ = time_ + lineTime_;
5021 -unsigned long LyCounter::nextLineCycle(unsigned const lineCycle, unsigned long const cc) const {
5022 - unsigned long tmp = time_ + (lineCycle << ds_);
5023 +unsigned LyCounter::nextLineCycle(unsigned const lineCycle, unsigned const cc) const {
5024 + unsigned tmp = time_ + (lineCycle << ds_);
5025 if (tmp - cc > lineTime_)
5026 tmp -= lineTime_;
5028 return tmp;
5031 -unsigned long LyCounter::nextFrameCycle(unsigned long const frameCycle, unsigned long const cc) const {
5032 - unsigned long tmp = time_ + (((153U - ly()) * 456U + frameCycle) << ds_);
5033 +unsigned LyCounter::nextFrameCycle(unsigned const frameCycle, unsigned const cc) const {
5034 + unsigned tmp = time_ + (((153U - ly()) * 456U + frameCycle) << ds_);
5035 if (tmp - cc > 70224U << ds_)
5036 tmp -= 70224U << ds_;
5038 return tmp;
5041 -void LyCounter::reset(unsigned long videoCycles, unsigned long lastUpdate) {
5042 +void LyCounter::reset(unsigned videoCycles, unsigned lastUpdate) {
5043 ly_ = videoCycles / 456;
5044 time_ = lastUpdate + ((456 - (videoCycles - ly_ * 456ul)) << isDoubleSpeed());
5046 diff --git a/libgambatte/src/video/ly_counter.h b/libgambatte/src/video/ly_counter.h
5047 index 1defd1a..7c4d834 100644
5048 --- a/libgambatte/src/video/ly_counter.h
5049 +++ b/libgambatte/src/video/ly_counter.h
5050 @@ -18,6 +18,11 @@
5051 ***************************************************************************/
5052 #ifndef LY_COUNTER_H
5053 #define LY_COUNTER_H
5054 +#include "../loadsave.h"
5057 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
5058 +// - Make it rerecording-friendly.
5060 namespace gambatte {
5062 @@ -29,24 +34,31 @@ public:
5063 void doEvent();
5064 bool isDoubleSpeed() const { return ds_; }
5066 - unsigned long frameCycles(unsigned long cc) const {
5067 + unsigned frameCycles(unsigned cc) const {
5068 return ly_ * 456ul + lineCycles(cc);
5071 - unsigned lineCycles(unsigned long cc) const {
5072 + unsigned lineCycles(unsigned cc) const {
5073 return 456u - ((time_ - cc) >> isDoubleSpeed());
5076 unsigned lineTime() const { return lineTime_; }
5077 unsigned ly() const { return ly_; }
5078 - unsigned long nextLineCycle(unsigned lineCycle, unsigned long cycleCounter) const;
5079 - unsigned long nextFrameCycle(unsigned long frameCycle, unsigned long cycleCounter) const;
5080 - void reset(unsigned long videoCycles, unsigned long lastUpdate);
5082 + void loadOrSave(loadsave& state) {
5083 + state(time_);
5084 + state(lineTime_);
5085 + state(ly_);
5086 + state(ds_);
5088 + unsigned nextLineCycle(unsigned lineCycle, unsigned cycleCounter) const;
5089 + unsigned nextFrameCycle(unsigned frameCycle, unsigned cycleCounter) const;
5090 + void reset(unsigned videoCycles, unsigned lastUpdate);
5091 void setDoubleSpeed(bool ds);
5092 - unsigned long time() const { return time_; }
5093 + unsigned time() const { return time_; }
5095 private:
5096 - unsigned long time_;
5097 + unsigned time_;
5098 unsigned short lineTime_;
5099 unsigned char ly_;
5100 bool ds_;
5101 diff --git a/libgambatte/src/video/lyc_irq.cpp b/libgambatte/src/video/lyc_irq.cpp
5102 index 3c468e2..127d589 100644
5103 --- a/libgambatte/src/video/lyc_irq.cpp
5104 +++ b/libgambatte/src/video/lyc_irq.cpp
5105 @@ -23,6 +23,10 @@
5106 #include "savestate.h"
5107 #include <algorithm>
5110 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
5111 +// - Make it rerecording-friendly.
5113 namespace gambatte {
5115 LycIrq::LycIrq()
5116 @@ -35,16 +39,16 @@ LycIrq::LycIrq()
5120 -static unsigned long schedule(unsigned statReg,
5121 - unsigned lycReg, LyCounter const &lyCounter, unsigned long cc) {
5122 +static unsigned schedule(unsigned statReg,
5123 + unsigned lycReg, LyCounter const &lyCounter, unsigned cc) {
5124 return (statReg & lcdstat_lycirqen) && lycReg < 154
5125 ? lyCounter.nextFrameCycle(lycReg ? lycReg * 456 : 153 * 456 + 8, cc)
5126 - : static_cast<unsigned long>(disabled_time);
5127 + : static_cast<unsigned>(disabled_time);
5130 void LycIrq::regChange(unsigned const statReg,
5131 - unsigned const lycReg, LyCounter const &lyCounter, unsigned long const cc) {
5132 - unsigned long const timeSrc = schedule(statReg, lycReg, lyCounter, cc);
5133 + unsigned const lycReg, LyCounter const &lyCounter, unsigned const cc) {
5134 + unsigned const timeSrc = schedule(statReg, lycReg, lyCounter, cc);
5135 statRegSrc_ = statReg;
5136 lycRegSrc_ = lycReg;
5137 time_ = std::min(time_, timeSrc);
5138 @@ -95,7 +99,7 @@ void LycIrq::saveState(SaveState &state) const {
5139 state.ppu.lyc = lycReg_;
5142 -void LycIrq::reschedule(LyCounter const &lyCounter, unsigned long cc) {
5143 +void LycIrq::reschedule(LyCounter const &lyCounter, unsigned cc) {
5144 time_ = std::min(schedule(statReg_ , lycReg_ , lyCounter, cc),
5145 schedule(statRegSrc_, lycRegSrc_, lyCounter, cc));
5147 diff --git a/libgambatte/src/video/lyc_irq.h b/libgambatte/src/video/lyc_irq.h
5148 index 6dd7911..a24a9ba 100644
5149 --- a/libgambatte/src/video/lyc_irq.h
5150 +++ b/libgambatte/src/video/lyc_irq.h
5151 @@ -19,6 +19,12 @@
5152 #ifndef VIDEO_LYC_IRQ_H
5153 #define VIDEO_LYC_IRQ_H
5156 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
5157 +// - Make it rerecording-friendly.
5159 +#include "../loadsave.h"
5161 namespace gambatte {
5163 struct SaveState;
5164 @@ -31,21 +37,30 @@ public:
5165 unsigned lycReg() const { return lycRegSrc_; }
5166 void loadState(SaveState const &state);
5167 void saveState(SaveState &state) const;
5168 - unsigned long time() const { return time_; }
5169 + void loadOrSave(loadsave& state) {
5170 + state(time_);
5171 + state(lycRegSrc_);
5172 + state(statRegSrc_);
5173 + state(lycReg_);
5174 + state(statReg_);
5175 + state(cgb_);
5178 + unsigned time() const { return time_; }
5179 void setCgb(bool cgb) { cgb_ = cgb; }
5180 void lcdReset();
5181 - void reschedule(LyCounter const &lyCounter, unsigned long cc);
5182 + void reschedule(LyCounter const &lyCounter, unsigned cc);
5184 - void statRegChange(unsigned statReg, LyCounter const &lyCounter, unsigned long cc) {
5185 + void statRegChange(unsigned statReg, LyCounter const &lyCounter, unsigned cc) {
5186 regChange(statReg, lycRegSrc_, lyCounter, cc);
5189 - void lycRegChange(unsigned lycReg, LyCounter const &lyCounter, unsigned long cc) {
5190 + void lycRegChange(unsigned lycReg, LyCounter const &lyCounter, unsigned cc) {
5191 regChange(statRegSrc_, lycReg, lyCounter, cc);
5194 private:
5195 - unsigned long time_;
5196 + unsigned time_;
5197 unsigned char lycRegSrc_;
5198 unsigned char statRegSrc_;
5199 unsigned char lycReg_;
5200 @@ -53,7 +68,7 @@ private:
5201 bool cgb_;
5203 void regChange(unsigned statReg, unsigned lycReg,
5204 - LyCounter const &lyCounter, unsigned long cc);
5205 + LyCounter const &lyCounter, unsigned cc);
5209 diff --git a/libgambatte/src/video/m0_irq.h b/libgambatte/src/video/m0_irq.h
5210 index f07f62f..fb0af1e 100644
5211 --- a/libgambatte/src/video/m0_irq.h
5212 +++ b/libgambatte/src/video/m0_irq.h
5213 @@ -20,13 +20,13 @@ public:
5216 void statRegChange(unsigned statReg,
5217 - unsigned long nextM0IrqTime, unsigned long cc, bool cgb) {
5218 + unsigned nextM0IrqTime, unsigned cc, bool cgb) {
5219 if (nextM0IrqTime - cc > cgb * 2U)
5220 statReg_ = statReg;
5223 void lycRegChange(unsigned lycReg,
5224 - unsigned long nextM0IrqTime, unsigned long cc,
5225 + unsigned nextM0IrqTime, unsigned cc,
5226 bool ds, bool cgb) {
5227 if (nextM0IrqTime - cc > cgb * 5 + 1U - ds)
5228 lycReg_ = lycReg;
5229 @@ -53,6 +53,11 @@ public:
5231 unsigned statReg() const { return statReg_; }
5233 + void loadOrSave(loadsave& state)
5235 + state(statReg_);
5236 + state(lycReg_);
5238 private:
5239 unsigned char statReg_;
5240 unsigned char lycReg_;
5241 diff --git a/libgambatte/src/video/next_m0_time.h b/libgambatte/src/video/next_m0_time.h
5242 index 5cea59d..9c7c0e3 100644
5243 --- a/libgambatte/src/video/next_m0_time.h
5244 +++ b/libgambatte/src/video/next_m0_time.h
5245 @@ -1,6 +1,12 @@
5246 #ifndef NEXT_M0_TIME_H_
5247 #define NEXT_M0_TIME_H_
5250 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
5251 +// - Make it rerecording-friendly.
5253 +#include "../loadsave.h"
5255 namespace gambatte {
5257 class NextM0Time {
5258 @@ -10,6 +16,9 @@ public:
5259 void invalidatePredictedNextM0Time() { predictedNextM0Time_ = 0; }
5260 unsigned predictedNextM0Time() const { return predictedNextM0Time_; }
5262 + void loadOrSave(loadsave& state) {
5263 + state(predictedNextM0Time_);
5265 private:
5266 unsigned predictedNextM0Time_;
5268 diff --git a/libgambatte/src/video/ppu.cpp b/libgambatte/src/video/ppu.cpp
5269 index fd0dc07..485b0d4 100644
5270 --- a/libgambatte/src/video/ppu.cpp
5271 +++ b/libgambatte/src/video/ppu.cpp
5272 @@ -449,7 +449,7 @@ static void doFullTilesUnrolledDmg(PPUPriv &p, int const xend, uint_least32_t *c
5274 unsigned const attrib = p.spriteList[i].attrib;
5275 unsigned spword = p.spwordList[i];
5276 - unsigned long const *const spPalette = p.spPalette + (attrib >> 2 & 4);
5277 + const uint_least32_t *const spPalette = p.spPalette + (attrib >> 2 & 4);
5278 uint_least32_t *d = dst + pos;
5280 if (!(attrib & attr_bgpriority)) {
5281 @@ -564,7 +564,7 @@ static void doFullTilesUnrolledCgb(PPUPriv &p, int const xend, uint_least32_t *c
5282 xpos += n;
5284 do {
5285 - unsigned long const *const bgPalette = p.bgPalette + (nattrib & 7) * 4;
5286 + uint_least32_t const *const bgPalette = p.bgPalette + (nattrib & 7) * 4;
5287 dst[0] = bgPalette[ ntileword & 0x0003 ];
5288 dst[1] = bgPalette[(ntileword & 0x000C) >> 2];
5289 dst[2] = bgPalette[(ntileword & 0x0030) >> 4];
5290 @@ -603,7 +603,7 @@ static void doFullTilesUnrolledCgb(PPUPriv &p, int const xend, uint_least32_t *c
5291 uint_least32_t *const dst = dbufline + (xpos - 8);
5292 unsigned const tileword = p.ntileword;
5293 unsigned const attrib = p.nattrib;
5294 - unsigned long const *const bgPalette = p.bgPalette + (attrib & 7) * 4;
5295 + uint_least32_t const *const bgPalette = p.bgPalette + (attrib & 7) * 4;
5297 dst[0] = bgPalette[ tileword & 0x0003 ];
5298 dst[1] = bgPalette[(tileword & 0x000C) >> 2];
5299 @@ -639,7 +639,7 @@ static void doFullTilesUnrolledCgb(PPUPriv &p, int const xend, uint_least32_t *c
5300 unsigned char const id = p.spriteList[i].oampos;
5301 unsigned const sattrib = p.spriteList[i].attrib;
5302 unsigned spword = p.spwordList[i];
5303 - unsigned long const *const spPalette = p.spPalette + (sattrib & 7) * 4;
5304 + uint_least32_t const *const spPalette = p.spPalette + (sattrib & 7) * 4;
5306 if (!((attrib | sattrib) & bgprioritymask)) {
5307 unsigned char *const idt = idtab + pos;
5308 @@ -805,7 +805,7 @@ static void plotPixel(PPUPriv &p) {
5311 unsigned const twdata = tileword & ((p.lcdc & 1) | p.cgb) * 3;
5312 - unsigned long pixel = p.bgPalette[twdata + (p.attrib & 7) * 4];
5313 + uint_least32_t pixel = p.bgPalette[twdata + (p.attrib & 7) * 4];
5314 int i = static_cast<int>(p.nextSprite) - 1;
5316 if (i >= 0 && int(p.spriteList[i].spx) > xpos - 8) {
5317 @@ -866,8 +866,8 @@ static void plotPixelIfNoSprite(PPUPriv &p) {
5318 plotPixel(p);
5321 -static unsigned long nextM2Time(PPUPriv const &p) {
5322 - unsigned long nextm2 = p.lyCounter.isDoubleSpeed()
5323 +static unsigned nextM2Time(PPUPriv const &p) {
5324 + unsigned nextm2 = p.lyCounter.isDoubleSpeed()
5325 ? p.lyCounter.time() + (weMasterCheckPriorToLyIncLineCycle(true ) + m2_ds_offset) * 2 - 456 * 2
5326 : p.lyCounter.time() + weMasterCheckPriorToLyIncLineCycle(p.cgb) - 456 ;
5327 if (p.lyCounter.ly() == 143)
5328 @@ -879,11 +879,11 @@ static unsigned long nextM2Time(PPUPriv const &p) {
5329 static void xpos168(PPUPriv &p) {
5330 p.lastM0Time = p.now - (p.cycles << p.lyCounter.isDoubleSpeed());
5332 - unsigned long const nextm2 = nextM2Time(p);
5333 + unsigned const nextm2 = nextM2Time(p);
5335 p.cycles = p.now >= nextm2
5336 - ? long((p.now - nextm2) >> p.lyCounter.isDoubleSpeed())
5337 - : -long((nextm2 - p.now) >> p.lyCounter.isDoubleSpeed());
5338 + ? signed((p.now - nextm2) >> p.lyCounter.isDoubleSpeed())
5339 + : -signed((nextm2 - p.now) >> p.lyCounter.isDoubleSpeed());
5341 nextCall(0, p.lyCounter.ly() == 143 ? M2_Ly0::f0_ : M2_LyNon0::f0_, p);
5343 @@ -1576,8 +1576,8 @@ std::size_t upperBound(T const a[], K e) {
5345 struct CycleState {
5346 PPUState const *state;
5347 - long cycle;
5348 - operator long() const { return cycle; }
5349 + signed cycle;
5350 + operator signed() const { return cycle; }
5353 static PPUState const * decodeM3LoopState(unsigned state) {
5354 @@ -1607,8 +1607,8 @@ static PPUState const * decodeM3LoopState(unsigned state) {
5355 return 0;
5358 -static long cyclesUntilM0Upperbound(PPUPriv const &p) {
5359 - long cycles = 168 - p.xpos + 6;
5360 +static signed cyclesUntilM0Upperbound(PPUPriv const &p) {
5361 + signed cycles = 168 - p.xpos + 6;
5362 for (unsigned i = p.nextSprite; i < 10 && p.spriteList[i].spx < 168; ++i)
5363 cycles += 11;
5365 @@ -1647,17 +1647,17 @@ static void loadSpriteList(PPUPriv &p, SaveState const &ss) {
5367 void PPU::loadState(SaveState const &ss, unsigned char const *const oamram) {
5368 PPUState const *const m3loopState = decodeM3LoopState(ss.ppu.state);
5369 - long const videoCycles = std::min(ss.ppu.videoCycles, 70223UL);
5370 + signed const videoCycles = std::min(ss.ppu.videoCycles, 70223U);
5371 bool const ds = p_.cgb & ss.mem.ioamhram.get()[0x14D] >> 7;
5372 - long const vcycs = videoCycles - ds * m2_ds_offset < 0
5373 + signed const vcycs = videoCycles - ds * m2_ds_offset < 0
5374 ? videoCycles - ds * m2_ds_offset + 70224
5375 : videoCycles - ds * m2_ds_offset;
5376 - long const lineCycles = static_cast<unsigned long>(vcycs) % 456;
5377 + signed const lineCycles = static_cast<unsigned>(vcycs) % 456;
5379 p_.now = ss.cpu.cycleCounter;
5380 p_.lcdc = ss.mem.ioamhram.get()[0x140];
5381 p_.lyCounter.setDoubleSpeed(ds);
5382 - p_.lyCounter.reset(std::min(ss.ppu.videoCycles, 70223ul), ss.cpu.cycleCounter);
5383 + p_.lyCounter.reset(std::min(ss.ppu.videoCycles, 70223u), ss.cpu.cycleCounter);
5384 p_.spriteMapper.loadState(ss, oamram);
5385 p_.winYPos = ss.ppu.winYPos;
5386 p_.scy = ss.mem.ioamhram.get()[0x142];
5387 @@ -1684,7 +1684,7 @@ void PPU::loadState(SaveState const &ss, unsigned char const *const oamram) {
5388 && lineCycles + cyclesUntilM0Upperbound(p_) < weMasterCheckPriorToLyIncLineCycle(p_.cgb)) {
5389 p_.nextCallPtr = m3loopState;
5390 p_.cycles = -1;
5391 - } else if (vcycs < 143 * 456L + static_cast<long>(m3StartLineCycle(p_.cgb)) + max_m3start_cycles) {
5392 + } else if (vcycs < 143 * 456L + static_cast<signed>(m3StartLineCycle(p_.cgb)) + max_m3start_cycles) {
5393 CycleState const lineCycleStates[] = {
5394 { &M3Start::f0_, m3StartLineCycle(p_.cgb) },
5395 { &M3Start::f1_, m3StartLineCycle(p_.cgb) + max_m3start_cycles },
5396 @@ -1715,9 +1715,9 @@ void PPU::reset(unsigned char const *oamram, unsigned char const *vram, bool cgb
5397 p_.spriteMapper.reset(oamram, cgb);
5400 -void PPU::resetCc(unsigned long const oldCc, unsigned long const newCc) {
5401 - unsigned long const dec = oldCc - newCc;
5402 - unsigned long const videoCycles = lcdcEn(p_) ? p_.lyCounter.frameCycles(p_.now) : 0;
5403 +void PPU::resetCc(unsigned const oldCc, unsigned const newCc) {
5404 + unsigned const dec = oldCc - newCc;
5405 + unsigned const videoCycles = lcdcEn(p_) ? p_.lyCounter.frameCycles(p_.now) : 0;
5407 p_.now -= dec;
5408 p_.lastM0Time = p_.lastM0Time ? p_.lastM0Time - dec : p_.lastM0Time;
5409 @@ -1725,8 +1725,8 @@ void PPU::resetCc(unsigned long const oldCc, unsigned long const newCc) {
5410 p_.spriteMapper.resetCycleCounter(oldCc, newCc);
5413 -void PPU::speedChange(unsigned long const cycleCounter) {
5414 - unsigned long const videoCycles = lcdcEn(p_) ? p_.lyCounter.frameCycles(p_.now) : 0;
5415 +void PPU::speedChange(unsigned const cycleCounter) {
5416 + unsigned const videoCycles = lcdcEn(p_) ? p_.lyCounter.frameCycles(p_.now) : 0;
5418 p_.spriteMapper.preSpeedChange(cycleCounter);
5419 p_.lyCounter.setDoubleSpeed(!p_.lyCounter.isDoubleSpeed());
5420 @@ -1741,12 +1741,12 @@ void PPU::speedChange(unsigned long const cycleCounter) {
5424 -unsigned long PPU::predictedNextXposTime(unsigned xpos) const {
5425 +unsigned PPU::predictedNextXposTime(unsigned xpos) const {
5426 return p_.now
5427 + (p_.nextCallPtr->predictCyclesUntilXpos_f(p_, xpos, -p_.cycles) << p_.lyCounter.isDoubleSpeed());
5430 -void PPU::setLcdc(unsigned const lcdc, unsigned long const cc) {
5431 +void PPU::setLcdc(unsigned const lcdc, unsigned const cc) {
5432 if ((p_.lcdc ^ lcdc) & lcdc & lcdc_en) {
5433 p_.now = cc;
5434 p_.lastM0Time = 0;
5435 @@ -1776,7 +1776,7 @@ void PPU::setLcdc(unsigned const lcdc, unsigned long const cc) {
5436 p_.lcdc = lcdc;
5439 -void PPU::update(unsigned long const cc) {
5440 +void PPU::update(unsigned const cc) {
5441 int const cycles = (cc - p_.now) >> p_.lyCounter.isDoubleSpeed();
5443 p_.now += cycles << p_.lyCounter.isDoubleSpeed();
5444 @@ -1788,4 +1788,70 @@ void PPU::update(unsigned long const cc) {
5448 +void PPUPriv::loadOrSave(loadsave& state)
5450 + state(bgPalette, 32);
5451 + state(spPalette, 32);
5453 + state.startEnumeration();
5454 + state.enumerate<const PPUState*>(nextCallPtr, NULL, 0);
5455 + state.enumerate<const PPUState*>(nextCallPtr, &M2_Ly0::f0_, 1);
5456 + state.enumerate<const PPUState*>(nextCallPtr, &M2_LyNon0::f0_, 2);
5457 + state.enumerate<const PPUState*>(nextCallPtr, &M2_LyNon0::f1_, 3);
5458 + state.enumerate<const PPUState*>(nextCallPtr, &M3Start::f0_, 4);
5459 + state.enumerate<const PPUState*>(nextCallPtr, &M3Start::f1_, 5);
5460 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::Tile::f0_, 6);
5461 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::Tile::f1_, 7);
5462 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::Tile::f2_, 8);
5463 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::Tile::f3_, 9);
5464 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::Tile::f4_, 10);
5465 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::Tile::f5_, 11);
5466 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::LoadSprites::f0_, 12);
5467 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::LoadSprites::f1_, 13);
5468 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::LoadSprites::f2_, 14);
5469 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::LoadSprites::f3_, 15);
5470 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::LoadSprites::f4_, 16);
5471 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::LoadSprites::f5_, 17);
5472 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::StartWindowDraw::f0_, 18);
5473 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::StartWindowDraw::f1_, 19);
5474 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::StartWindowDraw::f2_, 20);
5475 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::StartWindowDraw::f3_, 21);
5476 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::StartWindowDraw::f4_, 22);
5477 + state.enumerate<const PPUState*>(nextCallPtr, &M3Loop::StartWindowDraw::f5_, 23);
5478 + state.endEnumeration();
5480 + state(now);
5481 + state(lastM0Time);
5482 + state(cycles);
5483 + state(tileword);
5484 + state(ntileword);
5485 + lyCounter.loadOrSave(state);
5486 + spriteMapper.loadOrSave(state);
5487 + framebuf.loadOrSave(state);
5489 + for(size_t i = 0; i < 11; i++)
5490 + spriteList[i].loadOrSave(state);
5491 + state(spwordList, 11);
5492 + state(lcdc);
5493 + state(scy);
5494 + state(scx);
5495 + state(wy);
5496 + state(wy2);
5497 + state(wx);
5498 + state(winDrawState);
5499 + state(wscx);
5500 + state(winYPos);
5501 + state(reg0);
5502 + state(reg1);
5503 + state(attrib);
5504 + state(nattrib);
5505 + state(nextSprite);
5506 + state(currentSprite);
5507 + state(xpos);
5508 + state(endx);
5509 + state(cgb);
5510 + state(weMaster);
5515 diff --git a/libgambatte/src/video/ppu.h b/libgambatte/src/video/ppu.h
5516 index 1bd9a22..ea711b7 100644
5517 --- a/libgambatte/src/video/ppu.h
5518 +++ b/libgambatte/src/video/ppu.h
5519 @@ -19,27 +19,50 @@
5520 #ifndef PPU_H
5521 #define PPU_H
5524 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
5525 +// - Make it rerecording-friendly.
5527 +#include <cstring>
5528 +#include "video/ly_counter.h"
5529 +#include "video/sprite_mapper.h"
5530 #include "lcddef.h"
5531 #include "ly_counter.h"
5532 #include "sprite_mapper.h"
5533 #include "gbint.h"
5534 +#include "../loadsave.h"
5535 #include <cstddef>
5537 namespace gambatte {
5539 class PPUFrameBuf {
5540 public:
5541 - PPUFrameBuf() : buf_(0), fbline_(nullfbline()), pitch_(0) {}
5542 + PPUFrameBuf() : fbline_(nullfbline()), pitch_(160) { memset(buf_, 0, sizeof(buf_)); }
5543 uint_least32_t * fb() const { return buf_; }
5544 uint_least32_t * fbline() const { return fbline_; }
5545 std::ptrdiff_t pitch() const { return pitch_; }
5546 - void setBuf(uint_least32_t *buf, std::ptrdiff_t pitch) { buf_ = buf; pitch_ = pitch; fbline_ = nullfbline(); }
5547 void setFbline(unsigned ly) { fbline_ = buf_ ? buf_ + std::ptrdiff_t(ly) * pitch_ : nullfbline(); }
5548 + void blit(uint_least32_t *const buf, const int pitch) const {
5549 + for(unsigned i = 0; i < 144; i++)
5550 + memcpy(buf + i * static_cast<signed>(pitch), buf_ + i * 160, 160 * sizeof(buf[0]));
5552 + void loadOrSave(loadsave& state) {
5553 + state(buf_, 160*144);
5554 + state(pitch_);
5555 + bool var = (fbline_ != nullfbline());
5556 + state(var);
5557 + if(var) {
5558 + unsigned x = fbline_ - buf_;
5559 + state(x);
5560 + fbline_ = buf_ + x;
5561 + } else
5562 + fbline_ = nullfbline();
5565 private:
5566 - uint_least32_t *buf_;
5567 + mutable uint_least32_t buf_[160*144];
5568 uint_least32_t *fbline_;
5569 - std::ptrdiff_t pitch_;
5570 + int pitch_;
5572 static uint_least32_t * nullfbline() { static uint_least32_t nullfbline_[160]; return nullfbline_; }
5574 @@ -53,27 +76,34 @@ struct PPUState {
5577 struct PPUPriv {
5578 - unsigned long bgPalette[8 * 4];
5579 - unsigned long spPalette[8 * 4];
5580 - struct Sprite { unsigned char spx, oampos, line, attrib; } spriteList[11];
5581 - unsigned short spwordList[11];
5582 - unsigned char nextSprite;
5583 - unsigned char currentSprite;
5584 + uint_least32_t bgPalette[8 * 4];
5585 + uint_least32_t spPalette[8 * 4];
5587 unsigned char const *vram;
5588 PPUState const *nextCallPtr;
5590 - unsigned long now;
5591 - unsigned long lastM0Time;
5592 - long cycles;
5593 + unsigned now;
5594 + unsigned lastM0Time;
5595 + signed cycles;
5597 unsigned tileword;
5598 unsigned ntileword;
5600 - SpriteMapper spriteMapper;
5601 LyCounter lyCounter;
5602 + SpriteMapper spriteMapper;
5603 PPUFrameBuf framebuf;
5605 + struct Sprite {
5606 + unsigned char spx, oampos, line, attrib;
5607 + void loadOrSave(loadsave& state) {
5608 + state(spx);
5609 + state(oampos);
5610 + state(line);
5611 + state(attrib);
5613 + } spriteList[11];
5614 + unsigned short spwordList[11];
5616 unsigned char lcdc;
5617 unsigned char scy;
5618 unsigned char scx;
5619 @@ -87,12 +117,15 @@ struct PPUPriv {
5620 unsigned char reg1;
5621 unsigned char attrib;
5622 unsigned char nattrib;
5623 + unsigned char nextSprite;
5624 + unsigned char currentSprite;
5625 unsigned char xpos;
5626 unsigned char endx;
5628 bool cgb;
5629 bool weMaster;
5631 + void loadOrSave(loadsave& state);
5632 PPUPriv(NextM0Time &nextM0Time, unsigned char const *oamram, unsigned char const *vram);
5635 @@ -103,39 +136,42 @@ public:
5639 - unsigned long * bgPalette() { return p_.bgPalette; }
5640 + uint_least32_t * bgPalette() { return p_.bgPalette; }
5641 bool cgb() const { return p_.cgb; }
5642 void doLyCountEvent() { p_.lyCounter.doEvent(); }
5643 - unsigned long doSpriteMapEvent(unsigned long time) { return p_.spriteMapper.doEvent(time); }
5644 + unsigned doSpriteMapEvent(unsigned time) { return p_.spriteMapper.doEvent(time); }
5645 PPUFrameBuf const & frameBuf() const { return p_.framebuf; }
5647 - bool inactivePeriodAfterDisplayEnable(unsigned long cc) const {
5648 + bool inactivePeriodAfterDisplayEnable(unsigned cc) const {
5649 return p_.spriteMapper.inactivePeriodAfterDisplayEnable(cc);
5652 - unsigned long lastM0Time() const { return p_.lastM0Time; }
5653 + unsigned lastM0Time() const { return p_.lastM0Time; }
5654 unsigned lcdc() const { return p_.lcdc; }
5655 void loadState(SaveState const &state, unsigned char const *oamram);
5656 LyCounter const & lyCounter() const { return p_.lyCounter; }
5657 - unsigned long now() const { return p_.now; }
5658 - void oamChange(unsigned long cc) { p_.spriteMapper.oamChange(cc); }
5659 - void oamChange(unsigned char const *oamram, unsigned long cc) { p_.spriteMapper.oamChange(oamram, cc); }
5660 - unsigned long predictedNextXposTime(unsigned xpos) const;
5661 + unsigned now() const { return p_.now; }
5662 + void oamChange(unsigned cc) { p_.spriteMapper.oamChange(cc); }
5663 + void oamChange(unsigned char const *oamram, unsigned cc) { p_.spriteMapper.oamChange(oamram, cc); }
5664 + unsigned predictedNextXposTime(unsigned xpos) const;
5665 void reset(unsigned char const *oamram, unsigned char const *vram, bool cgb);
5666 - void resetCc(unsigned long oldCc, unsigned long newCc);
5667 + void resetCc(unsigned oldCc, unsigned newCc);
5668 void saveState(SaveState &ss) const;
5669 - void setFrameBuf(uint_least32_t *buf, std::ptrdiff_t pitch) { p_.framebuf.setBuf(buf, pitch); }
5670 - void setLcdc(unsigned lcdc, unsigned long cc);
5671 + void flipDisplay(uint_least32_t *buf, unsigned pitch) { p_.framebuf.blit(buf, pitch); }
5672 + void setLcdc(unsigned lcdc, unsigned cc);
5673 void setScx(unsigned scx) { p_.scx = scx; }
5674 void setScy(unsigned scy) { p_.scy = scy; }
5675 void setStatePtrs(SaveState &ss) { p_.spriteMapper.setStatePtrs(ss); }
5676 void setWx(unsigned wx) { p_.wx = wx; }
5677 void setWy(unsigned wy) { p_.wy = wy; }
5678 void updateWy2() { p_.wy2 = p_.wy; }
5679 - void speedChange(unsigned long cycleCounter);
5680 - unsigned long * spPalette() { return p_.spPalette; }
5681 - void update(unsigned long cc);
5682 + void speedChange(unsigned cycleCounter);
5683 + uint_least32_t * spPalette() { return p_.spPalette; }
5684 + void update(unsigned cc);
5686 + void loadOrSave(loadsave& state) {
5687 + p_.loadOrSave(state);
5689 private:
5690 PPUPriv p_;
5692 diff --git a/libgambatte/src/video/sprite_mapper.cpp b/libgambatte/src/video/sprite_mapper.cpp
5693 index 05ec6a8..ec1536e 100644
5694 --- a/libgambatte/src/video/sprite_mapper.cpp
5695 +++ b/libgambatte/src/video/sprite_mapper.cpp
5696 @@ -39,6 +39,10 @@ private:
5701 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
5702 +// - Make it rerecording-friendly.
5704 namespace gambatte {
5706 SpriteMapper::OamReader::OamReader(LyCounter const &lyCounter, unsigned char const *oamram)
5707 @@ -65,7 +69,7 @@ void SpriteMapper::OamReader::reset(unsigned char const *const oamram, bool cons
5711 -static unsigned toPosCycles(unsigned long const cc, LyCounter const &lyCounter) {
5712 +static unsigned toPosCycles(unsigned const cc, LyCounter const &lyCounter) {
5713 unsigned lc = lyCounter.lineCycles(cc) + 3 - lyCounter.isDoubleSpeed() * 3u;
5714 if (lc >= 456)
5715 lc -= 456;
5716 @@ -73,7 +77,7 @@ static unsigned toPosCycles(unsigned long const cc, LyCounter const &lyCounter)
5717 return lc;
5720 -void SpriteMapper::OamReader::update(unsigned long const cc) {
5721 +void SpriteMapper::OamReader::update(unsigned const cc) {
5722 if (cc > lu_) {
5723 if (changed()) {
5724 unsigned const lulc = toPosCycles(lu_, lyCounter_);
5725 @@ -115,7 +119,7 @@ void SpriteMapper::OamReader::update(unsigned long const cc) {
5729 -void SpriteMapper::OamReader::change(unsigned long cc) {
5730 +void SpriteMapper::OamReader::change(unsigned cc) {
5731 update(cc);
5732 lastChange_ = std::min(toPosCycles(lu_, lyCounter_), 80u);
5734 @@ -132,7 +136,7 @@ void SpriteMapper::OamReader::loadState(SaveState const &ss, unsigned char const
5735 change(lu_);
5738 -void SpriteMapper::OamReader::enableDisplay(unsigned long cc) {
5739 +void SpriteMapper::OamReader::enableDisplay(unsigned cc) {
5740 std::memset(buf_, 0x00, sizeof buf_);
5741 std::fill(szbuf_, szbuf_ + 40, false);
5742 lu_ = cc + (80 << lyCounter_.isDoubleSpeed());
5743 @@ -145,6 +149,7 @@ SpriteMapper::SpriteMapper(NextM0Time &nextM0Time,
5744 : nextM0Time_(nextM0Time)
5745 , oamReader_(lyCounter, oamram)
5747 + memset(spritemap_, 0, sizeof(spritemap_));
5748 clearMap();
5751 @@ -188,12 +193,12 @@ void SpriteMapper::sortLine(unsigned const ly) const {
5752 SpxLess(posbuf() + 1));
5755 -unsigned long SpriteMapper::doEvent(unsigned long const time) {
5756 +unsigned SpriteMapper::doEvent(unsigned const time) {
5757 oamReader_.update(time);
5758 mapSprites();
5759 return oamReader_.changed()
5760 ? time + oamReader_.lineTime()
5761 - : static_cast<unsigned long>(disabled_time);
5762 + : static_cast<unsigned>(disabled_time);
5766 diff --git a/libgambatte/src/video/sprite_mapper.h b/libgambatte/src/video/sprite_mapper.h
5767 index 7d8dbe1..341bce6 100644
5768 --- a/libgambatte/src/video/sprite_mapper.h
5769 +++ b/libgambatte/src/video/sprite_mapper.h
5770 @@ -19,8 +19,13 @@
5771 #ifndef SPRITE_MAPPER_H
5772 #define SPRITE_MAPPER_H
5775 +// Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
5776 +// - Make it rerecording-friendly.
5778 #include "ly_counter.h"
5779 #include "../savestate.h"
5780 +#include "../loadsave.h"
5782 namespace gambatte {
5784 @@ -32,17 +37,17 @@ public:
5785 LyCounter const &lyCounter,
5786 unsigned char const *oamram);
5787 void reset(unsigned char const *oamram, bool cgb);
5788 - unsigned long doEvent(unsigned long time);
5789 + unsigned doEvent(unsigned time);
5790 bool largeSprites(unsigned spNo) const { return oamReader_.largeSprites(spNo); }
5791 unsigned numSprites(unsigned ly) const { return num_[ly] & ~need_sorting_mask; }
5792 - void oamChange(unsigned long cc) { oamReader_.change(cc); }
5793 - void oamChange(unsigned char const *oamram, unsigned long cc) { oamReader_.change(oamram, cc); }
5794 + void oamChange(unsigned cc) { oamReader_.change(cc); }
5795 + void oamChange(unsigned char const *oamram, unsigned cc) { oamReader_.change(oamram, cc); }
5796 unsigned char const * oamram() const { return oamReader_.oam(); }
5797 unsigned char const * posbuf() const { return oamReader_.spritePosBuf(); }
5798 - void preSpeedChange(unsigned long cc) { oamReader_.update(cc); }
5799 - void postSpeedChange(unsigned long cc) { oamReader_.change(cc); }
5800 + void preSpeedChange(unsigned cc) { oamReader_.update(cc); }
5801 + void postSpeedChange(unsigned cc) { oamReader_.change(cc); }
5803 - void resetCycleCounter(unsigned long oldCc, unsigned long newCc) {
5804 + void resetCycleCounter(unsigned oldCc, unsigned newCc) {
5805 oamReader_.update(oldCc);
5806 oamReader_.resetCycleCounter(oldCc, newCc);
5808 @@ -57,7 +62,7 @@ public:
5811 void setStatePtrs(SaveState &state) { oamReader_.setStatePtrs(state); }
5812 - void enableDisplay(unsigned long cc) { oamReader_.enableDisplay(cc); }
5813 + void enableDisplay(unsigned cc) { oamReader_.enableDisplay(cc); }
5814 void saveState(SaveState &state) const { oamReader_.saveState(state); }
5816 void loadState(SaveState const &state, unsigned char const *oamram) {
5817 @@ -65,33 +70,48 @@ public:
5818 mapSprites();
5821 - bool inactivePeriodAfterDisplayEnable(unsigned long cc) const {
5822 + bool inactivePeriodAfterDisplayEnable(unsigned cc) const {
5823 return oamReader_.inactivePeriodAfterDisplayEnable(cc);
5826 - static unsigned long schedule(LyCounter const &lyCounter, unsigned long cc) {
5827 + static unsigned schedule(LyCounter const &lyCounter, unsigned cc) {
5828 return lyCounter.nextLineCycle(80, cc);
5831 + void loadOrSave(loadsave& state) {
5832 + state(spritemap_, 1440);
5833 + state(num_, 144);
5834 + oamReader_.loadOrSave(state);
5836 private:
5837 class OamReader {
5838 public:
5839 + void loadOrSave(loadsave& state) {
5840 + state(buf_, 80);
5841 + for(unsigned i = 0; i < 40; i++)
5842 + state(szbuf_[i]);
5843 + state(lu_);
5844 + state(lastChange_);
5845 + state(largeSpritesSrc_);
5846 + state(cgb_);
5849 OamReader(LyCounter const &lyCounter, unsigned char const *oamram);
5850 void reset(unsigned char const *oamram, bool cgb);
5851 - void change(unsigned long cc);
5852 - void change(unsigned char const *oamram, unsigned long cc) { change(cc); oamram_ = oamram; }
5853 + void change(unsigned cc);
5854 + void change(unsigned char const *oamram, unsigned cc) { change(cc); oamram_ = oamram; }
5855 bool changed() const { return lastChange_ != 0xFF; }
5856 bool largeSprites(unsigned spNo) const { return szbuf_[spNo]; }
5857 unsigned char const * oam() const { return oamram_; }
5858 - void resetCycleCounter(unsigned long oldCc, unsigned long newCc) { lu_ -= oldCc - newCc; }
5859 + void resetCycleCounter(unsigned oldCc, unsigned newCc) { lu_ -= oldCc - newCc; }
5860 void setLargeSpritesSrc(bool src) { largeSpritesSrc_ = src; }
5861 - void update(unsigned long cc);
5862 + void update(unsigned cc);
5863 unsigned char const * spritePosBuf() const { return buf_; }
5864 void setStatePtrs(SaveState &state);
5865 - void enableDisplay(unsigned long cc);
5866 + void enableDisplay(unsigned cc);
5867 void saveState(SaveState &state) const { state.ppu.enableDisplayM0Time = lu_; }
5868 void loadState(SaveState const &ss, unsigned char const *oamram);
5869 - bool inactivePeriodAfterDisplayEnable(unsigned long cc) const { return cc < lu_; }
5870 + bool inactivePeriodAfterDisplayEnable(unsigned cc) const { return cc < lu_; }
5871 unsigned lineTime() const { return lyCounter_.lineTime(); }
5873 private:
5874 @@ -99,7 +119,7 @@ private:
5875 bool szbuf_[40];
5876 LyCounter const &lyCounter_;
5877 unsigned char const *oamram_;
5878 - unsigned long lu_;
5879 + unsigned lu_;
5880 unsigned char lastChange_;
5881 bool largeSpritesSrc_;
5882 bool cgb_;
5883 @@ -115,6 +135,7 @@ private:
5884 void clearMap();
5885 void mapSprites();
5886 void sortLine(unsigned ly) const;
5892 2.1.3