gambatte fixes: Properly save MBC3 without RTC
[lsnes.git] / libgambatte-patches / svn537 / 0003-Breakpoints-debugging.patch
blobac97113e49f274d07ed7bed04bbfd1577abe0d10
1 From 6725b4545adc3e94e0344e5f904267349ce167ba Mon Sep 17 00:00:00 2001
2 From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
3 Date: Thu, 28 Nov 2013 22:05:32 +0200
4 Subject: [PATCH 3/9] Breakpoints & debugging
6 ---
7 libgambatte/include/gambatte.h | 23 +++++++++
8 libgambatte/src/cpu.cpp | 9 ++--
9 libgambatte/src/cpu.h | 7 +++
10 libgambatte/src/gambatte.cpp | 16 ++++++
11 libgambatte/src/mem/cartridge.cpp | 6 +++
12 libgambatte/src/mem/cartridge.h | 1 +
13 libgambatte/src/memory.cpp | 100 ++++++++++++++++++++++++++++++--------
14 libgambatte/src/memory.h | 93 ++++++++++++++++++++++++++++++++---
15 8 files changed, 225 insertions(+), 30 deletions(-)
17 diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h
18 index 5094906..ea2558c 100644
19 --- a/libgambatte/include/gambatte.h
20 +++ b/libgambatte/include/gambatte.h
21 @@ -18,6 +18,7 @@
22 ***************************************************************************/
23 #ifndef GAMBATTE_H
24 #define GAMBATTE_H
25 +#define GAMBATTE_SUPPORTS_ADV_DEBUG
27 #include "gbint.h"
28 #include "inputgetter.h"
29 @@ -25,6 +26,8 @@
30 #include <cstddef>
31 #include <string>
32 #include <vector>
33 +#include <functional>
34 +#include <map>
37 // Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
38 @@ -34,6 +37,23 @@ namespace gambatte {
40 enum { BG_PALETTE = 0, SP1_PALETTE = 1, SP2_PALETTE = 2 };
42 +struct debugbuffer
44 + //1 => Read, 2 => Write, 4 => Execute, 8 => Cheat
45 + uint8_t* wram; //32kB, id1.
46 + uint8_t* ioamhram; //512 bytes, id2.
47 + uint8_t* cart; //As needed, id3.
48 + uint8_t* sram; //As needed, id4.
49 + uint8_t* bus; //64kB, id0
50 + std::map<unsigned, uint8_t> wramcheat;
51 + std::map<unsigned, uint8_t> sramcheat;
52 + std::map<unsigned, uint8_t> cartcheat;
53 + std::function<void(unsigned, unsigned, uint8_t, bool)> read;
54 + std::function<void(unsigned, unsigned, uint8_t)> write;
55 + std::function<void(uint16_t)> trace;
56 + bool trace_cpu;
57 +};
59 class GB {
60 public:
61 GB();
62 @@ -259,6 +279,9 @@ public:
64 uint32_t get_cpureg(enum cpu_register reg);
65 void set_cpureg(enum cpu_register reg, uint32_t val);
66 + void set_debug_buffer(debugbuffer& dbgbuf);
67 + uint8_t bus_read(unsigned addr);
68 + void bus_write(unsigned addr, uint8_t val);
69 private:
70 void preload_common();
71 void postload_common(const unsigned flags);
72 diff --git a/libgambatte/src/cpu.cpp b/libgambatte/src/cpu.cpp
73 index 06400c5..40a81e6 100644
74 --- a/libgambatte/src/cpu.cpp
75 +++ b/libgambatte/src/cpu.cpp
76 @@ -154,8 +154,8 @@ void CPU::loadOrSave(loadsave& state)
77 #define de() ( d << 8 | e )
78 #define hl() ( h << 8 | l )
80 -#define READ(dest, addr) do { (dest) = mem_.read(addr, cycleCounter); cycleCounter += 4; } while (0)
81 -#define PC_READ(dest) do { (dest) = mem_.read(pc, cycleCounter); pc = (pc + 1) & 0xFFFF; cycleCounter += 4; } while (0)
82 +#define READ(dest, addr) do { (dest) = mem_.read(addr, cycleCounter, false); cycleCounter += 4; } while (0)
83 +#define PC_READ(dest) do { (dest) = mem_.read(pc, cycleCounter, true); pc = (pc + 1) & 0xFFFF; cycleCounter += 4; } while (0)
84 #define FF_READ(dest, addr) do { (dest) = mem_.ff_read(addr, cycleCounter); cycleCounter += 4; } while (0)
86 #define WRITE(addr, data) do { mem_.write(addr, data, cycleCounter); cycleCounter += 4; } while (0)
87 @@ -525,7 +525,8 @@ void CPU::process(unsigned const cycles) {
89 } else while (cycleCounter < mem_.nextEventTime()) {
90 unsigned char opcode;
92 + if(__builtin_expect(mem_.get_debug()->trace_cpu, 0))
93 + mem_.get_debug()->trace(pc);
94 PC_READ(opcode);
96 if (skip_) {
97 @@ -923,7 +924,7 @@ void CPU::process(unsigned const cycles) {
98 case 0x3A:
100 unsigned addr = hl();
101 - a = mem_.read(addr, cycleCounter);
102 + a = mem_.read(addr, cycleCounter, false);
103 cycleCounter += 4;
105 addr = (addr - 1) & 0xFFFF;
106 diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h
107 index 224ba0b..e7e46ff 100644
108 --- a/libgambatte/src/cpu.h
109 +++ b/libgambatte/src/cpu.h
110 @@ -51,6 +51,11 @@ public:
111 mem_.setSaveDir(sdir);
114 + void set_debug_buffer(debugbuffer& dbgbuf)
116 + mem_.set_debug_buffer(dbgbuf);
119 std::string const saveBasePath() const {
120 return mem_.saveBasePath();
122 @@ -87,6 +92,8 @@ public:
123 std::pair<unsigned char*, size_t> getSaveRam() { return mem_.getSaveRam(); }
124 std::pair<unsigned char*, size_t> getIoRam() { return mem_.getIoRam(); }
125 std::pair<unsigned char*, size_t> getVideoRam() { return mem_.getVideoRam(); };
126 + uint8_t bus_read(unsigned addr) { return mem_.read(addr, cycleCounter_, false); }
127 + void bus_write(unsigned addr, uint8_t val) { mem_.write(addr, val, cycleCounter_); }
129 unsigned cycleCounter_;
130 unsigned short pc_;
131 diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp
132 index a61e177..47f894e 100644
133 --- a/libgambatte/src/gambatte.cpp
134 +++ b/libgambatte/src/gambatte.cpp
135 @@ -346,4 +346,20 @@ void GB::set_cpureg(enum cpu_register _reg, uint32_t val)
136 default: break;
140 +void GB::set_debug_buffer(debugbuffer& dbgbuf)
142 + p_->cpu.set_debug_buffer(dbgbuf);
145 +uint8_t GB::bus_read(unsigned addr)
147 + return p_->cpu.bus_read(addr);
150 +void GB::bus_write(unsigned addr, uint8_t val)
152 + p_->cpu.bus_write(addr, val);
156 diff --git a/libgambatte/src/mem/cartridge.cpp b/libgambatte/src/mem/cartridge.cpp
157 index d593dc5..1775139 100644
158 --- a/libgambatte/src/mem/cartridge.cpp
159 +++ b/libgambatte/src/mem/cartridge.cpp
160 @@ -858,6 +858,12 @@ std::pair<unsigned char*, size_t> Cartridge::getWorkRam() {
161 return std::make_pair(memptrs_.wramdata(0), worksize);
164 +std::pair<unsigned char*, size_t> Cartridge::getCartRom()
166 + size_t worksize = memptrs_.romdataend() - memptrs_.romdata(0);
167 + return std::make_pair(memptrs_.romdata(0), worksize);
170 Cartridge::Cartridge(time_t (**_getCurrentTime)())
171 : rtc_(_getCurrentTime) {
172 memoryCartridge = true;
173 diff --git a/libgambatte/src/mem/cartridge.h b/libgambatte/src/mem/cartridge.h
174 index dd342b6..3a0466c 100644
175 --- a/libgambatte/src/mem/cartridge.h
176 +++ b/libgambatte/src/mem/cartridge.h
177 @@ -81,6 +81,7 @@ public:
178 void loadOrSave(loadsave& state);
179 void setRtcBase(time_t time) { rtc_.setBaseTime(time); }
180 time_t getRtcBase() { return rtc_.getBaseTime(); }
181 + std::pair<unsigned char*, size_t> getCartRom();
182 std::pair<unsigned char*, size_t> getWorkRam();
183 std::pair<unsigned char*, size_t> getSaveRam();
184 std::pair<unsigned char*, size_t> getVideoRam();
185 diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp
186 index cc76f96..c42af88 100644
187 --- a/libgambatte/src/memory.cpp
188 +++ b/libgambatte/src/memory.cpp
189 @@ -234,7 +234,7 @@ unsigned Memory::event(unsigned cc) {
190 unsigned const src = dmaSrc++ & 0xFFFF;
191 unsigned const data = (src & 0xE000) == 0x8000 || src > 0xFDFF
192 ? 0xFF
193 - : read(src, cc);
194 + : read(src, cc, false);
196 cc += 2 << doubleSpeed;
198 @@ -550,18 +550,31 @@ static bool isInOamDmaConflictArea(OamDmaSrc const oamDmaSrc, unsigned const p,
199 && p - a[oamDmaSrc].exceptAreaLower >= a[oamDmaSrc].exceptAreaWidth;
202 -unsigned Memory::nontrivial_read(unsigned const p, unsigned const cc) {
203 +unsigned Memory::nontrivial_read(unsigned const p, unsigned const cc, bool exec) {
204 if (p < 0xFF80) {
205 if (lastOamDmaUpdate_ != disabled_time) {
206 updateOamDma(cc);
208 - if (isInOamDmaConflictArea(cart_.oamDmaSrc(), p, isCgb()) && oamDmaPos_ < 0xA0)
209 + if (isInOamDmaConflictArea(cart_.oamDmaSrc(), p, isCgb()) && oamDmaPos_ < 0xA0) {
210 return ioamhram_[oamDmaPos_];
214 if (p < 0xC000) {
215 - if (p < 0x8000)
216 - return cart_.romdata(p >> 14)[p];
217 + if (p < 0x8000) {
218 + const unsigned char* aaddr = cart_.romdata(p >> 14) + p;
219 + auto a = cart_.getCartRom();
220 + if(aaddr >= a.first && aaddr < a.first + a.second)
221 + if(__builtin_expect(dbg->cart[aaddr - a.first] & (exec ? 0x4C : 0x19), 0)) {
222 + if(dbg->cart[aaddr - a.first] & (exec ? 0x44 : 0x11))
223 + dbg->read(3, aaddr - a.first, *aaddr, exec);
224 + if(dbg->cart[aaddr - a.first] & 8) {
225 + auto itr = dbg->cartcheat.find(aaddr - a.first);
226 + if(itr != dbg->cartcheat.end()) return itr->second;
229 + return *aaddr;
232 if (p < 0xA000) {
233 if (!lcd_.vramAccessible(cc))
234 @@ -570,23 +583,52 @@ unsigned Memory::nontrivial_read(unsigned const p, unsigned const cc) {
235 return cart_.vrambankptr()[p];
238 - if (cart_.rsrambankptr())
239 - return cart_.rsrambankptr()[p];
240 + if (cart_.rsrambankptr()) {
241 + const unsigned char* aaddr = cart_.rsrambankptr() + p;
242 + auto a = cart_.getSaveRam();
243 + if(aaddr >= a.first && aaddr < a.first + a.second)
244 + if(__builtin_expect(dbg->sram[aaddr - a.first] & (exec ? 0x4C : 0x19), 0)) {
245 + if(dbg->sram[aaddr - a.first] & (exec ? 0x44 : 0x11))
246 + dbg->read(4, aaddr - a.first, *aaddr, exec);
247 + if(dbg->sram[aaddr - a.first] & 8) {
248 + auto itr = dbg->sramcheat.find(aaddr - a.first);
249 + if(itr != dbg->sramcheat.end()) return itr->second;
252 + return *aaddr;
255 return cart_.rtcRead();
258 - if (p < 0xFE00)
259 - return cart_.wramdata(p >> 12 & 1)[p & 0xFFF];
260 + if (p < 0xFE00) {
261 + unsigned char* aaddr = cart_.wramdata(p >> 12 & 1) + (p & 0xFFF);
262 + auto a = cart_.getWorkRam();
263 + if(aaddr >= a.first && aaddr < a.first + a.second)
264 + if(__builtin_expect(dbg->wram[aaddr - a.first] & (exec ? 0x4C : 0x19), 0)) {
265 + if(dbg->wram[aaddr - a.first] & (exec ? 0x44 : 0x11))
266 + dbg->read(1, aaddr - a.first, *aaddr, exec);
267 + if(dbg->wram[aaddr - a.first] & 8) {
268 + auto itr = dbg->wramcheat.find(aaddr - a.first);
269 + if(itr != dbg->wramcheat.end()) return itr->second;
272 + return *aaddr;
275 long const ffp = long(p) - 0xFF00;
276 - if (ffp >= 0)
277 - return nontrivial_ff_read(ffp, cc);
278 + if (ffp >= 0) {
279 + uint8_t v = nontrivial_ff_read(ffp, cc);
280 + if(__builtin_expect(dbg->ioamhram[ffp + 0x100] & (exec ? 0x44 : 0x11), 0))
281 + dbg->read(2, ffp + 0x100, v, exec);
282 + return v;
285 if (!lcd_.oamReadable(cc) || oamDmaPos_ < 0xA0)
286 return 0xFF;
289 + if(__builtin_expect(dbg->ioamhram[p - 0xFE00] & (exec ? 0x44 : 0x11), 0))
290 + dbg->read(2, p - 0xFE00, ioamhram_[p - 0xFE00], exec);
291 return ioamhram_[p - 0xFE00];
294 @@ -1023,18 +1065,32 @@ void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned co
295 if (p < 0xFE00) {
296 if (p < 0xA000) {
297 if (p < 0x8000) {
298 + //Being a write on MBC, this is not ROM write.
299 cart_.mbcWrite(p, data);
300 } else if (lcd_.vramAccessible(cc)) {
301 lcd_.vramChange(cc);
302 cart_.vrambankptr()[p] = data;
304 } else if (p < 0xC000) {
305 - if (cart_.wsrambankptr())
306 - cart_.wsrambankptr()[p] = data;
307 - else
308 + if (cart_.wsrambankptr()) {
309 + unsigned char* aaddr = cart_.wsrambankptr() + p;
310 + auto a = cart_.getSaveRam();
311 + if(aaddr >= a.first && aaddr < a.first + a.second)
312 + if(__builtin_expect(dbg->sram[aaddr - a.first] & 0x22, 0))
313 + dbg->write(4, aaddr - a.first, data);
314 + *aaddr = data;
315 + } else {
316 + //Being I/O write, this is not write on SRAM.
317 cart_.rtcWrite(data);
318 - } else
319 - cart_.wramdata(p >> 12 & 1)[p & 0xFFF] = data;
321 + } else {
322 + unsigned char* aaddr = cart_.wramdata(p >> 12 & 1) + (p & 0xFFF);
323 + auto a = cart_.getWorkRam();
324 + if(aaddr >= a.first && aaddr < a.first + a.second)
325 + if(__builtin_expect(dbg->wram[aaddr - a.first] & 0x22, 0))
326 + dbg->write(1, aaddr - a.first, data);
327 + *aaddr = data;
329 } else if (p - 0xFF80u >= 0x7Fu) {
330 long const ffp = long(p) - 0xFF00;
331 if (ffp < 0) {
332 @@ -1042,10 +1098,16 @@ void Memory::nontrivial_write(unsigned const p, unsigned const data, unsigned co
333 lcd_.oamChange(cc);
334 ioamhram_[p - 0xFE00] = data;
336 - } else
337 + } else {
338 + if(__builtin_expect(dbg->ioamhram[ffp + 0x100] & 0x22, 0))
339 + dbg->write(2, ffp + 0x100, data);
340 nontrivial_ff_write(ffp, data, cc);
341 - } else
343 + } else {
344 + if(__builtin_expect(dbg->ioamhram[p - 0xFE00] & 0x22, 0))
345 + dbg->write(2, p - 0xFE00, data);
346 ioamhram_[p - 0xFE00] = data;
350 void Memory::postLoadRom()
351 diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h
352 index a531930..4a252b7 100644
353 --- a/libgambatte/src/memory.h
354 +++ b/libgambatte/src/memory.h
355 @@ -23,6 +23,7 @@
356 // Modified 2012-07-10 to 2012-07-14 by H. Ilari Liusvaara
357 // - Make it rerecording-friendly.
359 +#include "gambatte.h"
360 #include "mem/cartridge.h"
361 #include "interrupter.h"
362 #include "pakinfo.h"
363 @@ -71,22 +72,99 @@ public:
364 void ei(unsigned cycleCounter) { if (!ime()) { intreq_.ei(cycleCounter); } }
365 void di() { intreq_.di(); }
367 + void set_debug_buffer(debugbuffer& dbgbuf)
369 + dbg = &dbgbuf;
372 unsigned ff_read(unsigned p, unsigned cc) {
373 - return p < 0x80 ? nontrivial_ff_read(p, cc) : ioamhram_[p + 0x100];
374 + uint8_t v = p < 0x80 ? nontrivial_ff_read(p, cc) : ioamhram_[p + 0x100];
375 + if(__builtin_expect(dbg->ioamhram[0x100 + p] & 1, 0))
376 + dbg->read(2, 0x100 + p, v, false);
377 + if(__builtin_expect(dbg->bus[0xFF00 + p] & 1, 0))
378 + dbg->read(0, 0xFF00 + p, v, false);
379 + return v;
382 + inline uint8_t do_read_trap(const uint8_t* addr, std::pair<unsigned char*, size_t> area, unsigned clazz,
383 + const uint8_t* dbgflags, std::map<unsigned, uint8_t>& cheats, uint8_t v, uint8_t mask, bool exec)
385 + if(addr >= area.first && addr < area.first + area.second) {
386 + if(__builtin_expect(dbgflags[addr - area.first] & mask, 0)) {
387 + if(dbgflags[addr - area.first] & (mask & 77))
388 + dbg->read(clazz, addr - area.first, v, exec);
389 + if(__builtin_expect(dbgflags[addr - area.first] & 8, 0)) {
390 + auto itr = cheats.find(addr - area.first);
391 + if(itr != cheats.end()) v = itr->second;
395 + return v;
398 - unsigned read(unsigned p, unsigned cc) {
399 - return cart_.rmem(p >> 12) ? cart_.rmem(p >> 12)[p] : nontrivial_read(p, cc);
400 + inline void do_write_trap(const uint8_t* addr, std::pair<unsigned char*, size_t> area, unsigned clazz,
401 + const uint8_t* dbgflags, uint8_t v)
403 + if(addr >= area.first && addr < area.first + area.second)
404 + if(__builtin_expect(dbgflags[addr - area.first] & 0x22, 0))
405 + dbg->write(clazz, addr - area.first, v);
408 + unsigned read(unsigned p, unsigned cc, bool exec) {
409 + uint8_t mask = exec ? 0x4C : 0x19;
410 + const unsigned char* memblock = cart_.rmem(p >> 12);
411 + uint8_t v = memblock ? memblock[p] : nontrivial_read(p, cc, exec);
412 + uint8_t v2 = v;
413 + if(memblock) {
414 + if(p >= 0xFE00) { //IOAMHRAM.
415 + if(__builtin_expect(dbg->ioamhram[p - 0xFE00] & mask, 0))
416 + dbg->read(2, 0x100 + p, v, false);
417 + } else {
418 + const uint8_t* addr = memblock + p;
419 + static void* targets[8] = {&&cart, &&cart, &&cart, &&cart, &&out, &&sram, &&wram,
420 + &&wram};
421 + goto *targets[p >> 13];
422 +wram:
423 + v2 = do_read_trap(addr, cart_.getWorkRam(), 1, dbg->wram, dbg->wramcheat, v, mask, exec);
424 + goto out;
425 +sram:
426 + v2 = do_read_trap(addr, cart_.getSaveRam(), 4, dbg->sram, dbg->sramcheat, v, mask, exec);
427 + goto out;
428 +cart:
429 + v2 = do_read_trap(addr, cart_.getCartRom(), 3, dbg->cart, dbg->cartcheat, v, mask, exec);
430 + goto out;
432 +out: ;
434 + if(__builtin_expect(dbg->bus[p] & mask, 0))
435 + dbg->read(0, p, v, false);
436 + return v2;
439 void write(unsigned p, unsigned data, unsigned cc) {
440 - if (cart_.wmem(p >> 12)) {
441 - cart_.wmem(p >> 12)[p] = data;
442 + if(__builtin_expect(dbg->bus[0xFF00 + p] & 0x22, 0))
443 + dbg->write(0, p, data);
444 + unsigned char* memblock = cart_.wmem(p >> 12);
445 + if(memblock) {
446 + if(p >= 0xFE00) //IOAMHRAM.
447 + if(__builtin_expect(dbg->ioamhram[p - 0xFE00] & 2, 0))
448 + dbg->write(2, 0x100 + p, data);
449 + uint8_t* addr = memblock + p;
450 + do_write_trap(addr, cart_.getWorkRam(), 1, dbg->wram, data);
451 + do_write_trap(addr, cart_.getSaveRam(), 4, dbg->sram, data);
452 + do_write_trap(addr, cart_.getCartRom(), 3, dbg->cart, data);
454 + if (memblock) {
455 + memblock[p] = data;
456 } else
457 nontrivial_write(p, data, cc);
460 void ff_write(unsigned p, unsigned data, unsigned cc) {
461 + if(__builtin_expect(dbg->ioamhram[0x100 + p] & 2, 0))
462 + dbg->write(2, 0x100 + p, data);
463 + if(__builtin_expect(dbg->bus[0xFF00 + p] & 2, 0))
464 + dbg->write(0, 0xFF00 + p, data);
465 if (p - 0x80u < 0x7Fu) {
466 ioamhram_[p + 0x100] = data;
467 } else
468 @@ -119,8 +197,9 @@ public:
469 void setDmgPaletteColor(unsigned palNum, unsigned colorNum, uint_least32_t rgb32);
470 void setGameGenie(std::string const &codes) { cart_.setGameGenie(codes); }
471 void setGameShark(std::string const &codes) { interrupter_.setGameShark(codes); }
473 + debugbuffer* get_debug() { return dbg; }
474 private:
475 + debugbuffer* dbg;
476 Cartridge cart_;
477 unsigned char ioamhram_[0x200];
478 InputGetter *getInput_;
479 @@ -147,7 +226,7 @@ private:
480 void endOamDma(unsigned cycleCounter);
481 unsigned char const * oamDmaSrcPtr() const;
482 unsigned nontrivial_ff_read(unsigned p, unsigned cycleCounter);
483 - unsigned nontrivial_read(unsigned p, unsigned cycleCounter);
484 + unsigned nontrivial_read(unsigned p, unsigned cycleCounter, bool exec);
485 void nontrivial_ff_write(unsigned p, unsigned data, unsigned cycleCounter);
486 void nontrivial_write(unsigned p, unsigned data, unsigned cycleCounter);
487 void updateSerial(unsigned cc);
489 2.1.3