Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libgambatte/src/mem/cartridge.cpp
2 views
1
/***************************************************************************
2
* Copyright (C) 2007-2010 by Sindre AamÄs *
3
* [email protected] *
4
* *
5
* This program is free software; you can redistribute it and/or modify *
6
* it under the terms of the GNU General Public License version 2 as *
7
* published by the Free Software Foundation. *
8
* *
9
* This program is distributed in the hope that it will be useful, *
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12
* GNU General Public License version 2 for more details. *
13
* *
14
* You should have received a copy of the GNU General Public License *
15
* version 2 along with this program; if not, write to the *
16
* Free Software Foundation, Inc., *
17
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
18
***************************************************************************/
19
#include "cartridge.h"
20
#include "../savestate.h"
21
#include <cstdio>
22
#include <cstring>
23
#include <fstream>
24
25
namespace gambatte {
26
27
namespace {
28
29
static unsigned toMulti64Rombank(const unsigned rombank) {
30
return (rombank >> 1 & 0x30) | (rombank & 0xF);
31
}
32
33
class DefaultMbc : public Mbc {
34
public:
35
virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const {
36
return (addr< 0x4000) == (bank == 0);
37
}
38
39
virtual void SyncState(NewState *ns, bool isReader)
40
{
41
}
42
};
43
44
class Mbc0 : public DefaultMbc {
45
MemPtrs &memptrs;
46
bool enableRam;
47
48
public:
49
explicit Mbc0(MemPtrs &memptrs)
50
: memptrs(memptrs),
51
enableRam(false)
52
{
53
}
54
55
virtual void romWrite(const unsigned P, const unsigned data) {
56
if (P < 0x2000) {
57
enableRam = (data & 0xF) == 0xA;
58
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
59
}
60
}
61
62
virtual void saveState(SaveState::Mem &ss) const {
63
ss.enableRam = enableRam;
64
}
65
66
virtual void loadState(const SaveState::Mem &ss) {
67
enableRam = ss.enableRam;
68
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
69
}
70
71
virtual void SyncState(NewState *ns, bool isReader)
72
{
73
NSS(enableRam);
74
}
75
};
76
77
static inline unsigned rambanks(const MemPtrs &memptrs) {
78
return static_cast<std::size_t>(memptrs.rambankdataend() - memptrs.rambankdata()) / 0x2000;
79
}
80
81
static inline unsigned rombanks(const MemPtrs &memptrs) {
82
return static_cast<std::size_t>(memptrs.romdataend() - memptrs.romdata() ) / 0x4000;
83
}
84
85
class Mbc1 : public DefaultMbc {
86
MemPtrs &memptrs;
87
unsigned char rombank;
88
unsigned char rambank;
89
bool enableRam;
90
bool rambankMode;
91
92
static unsigned adjustedRombank(unsigned bank) { return bank & 0x1F ? bank : bank | 1; }
93
void setRambank() const { memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, rambank & (rambanks(memptrs) - 1)); }
94
void setRombank() const { memptrs.setRombank(adjustedRombank(rombank & (rombanks(memptrs) - 1))); }
95
96
public:
97
explicit Mbc1(MemPtrs &memptrs)
98
: memptrs(memptrs),
99
rombank(1),
100
rambank(0),
101
enableRam(false),
102
rambankMode(false)
103
{
104
}
105
106
virtual void romWrite(const unsigned P, const unsigned data) {
107
switch (P >> 13 & 3) {
108
case 0:
109
enableRam = (data & 0xF) == 0xA;
110
setRambank();
111
break;
112
case 1:
113
rombank = rambankMode ? data & 0x1F : (rombank & 0x60) | (data & 0x1F);
114
setRombank();
115
break;
116
case 2:
117
if (rambankMode) {
118
rambank = data & 3;
119
setRambank();
120
} else {
121
rombank = (data << 5 & 0x60) | (rombank & 0x1F);
122
setRombank();
123
}
124
125
break;
126
case 3:
127
// Pretty sure this should take effect immediately, but I have a policy not to change old behavior
128
// unless I have something (eg. a verified test or a game) that justifies it.
129
rambankMode = data & 1;
130
break;
131
}
132
}
133
134
virtual void saveState(SaveState::Mem &ss) const {
135
ss.rombank = rombank;
136
ss.rambank = rambank;
137
ss.enableRam = enableRam;
138
ss.rambankMode = rambankMode;
139
}
140
141
virtual void loadState(const SaveState::Mem &ss) {
142
rombank = ss.rombank;
143
rambank = ss.rambank;
144
enableRam = ss.enableRam;
145
rambankMode = ss.rambankMode;
146
setRambank();
147
setRombank();
148
}
149
150
virtual void SyncState(NewState *ns, bool isReader)
151
{
152
NSS(rombank);
153
NSS(rambank);
154
NSS(enableRam);
155
NSS(rambankMode);
156
}
157
};
158
159
class Mbc1Multi64 : public Mbc {
160
MemPtrs &memptrs;
161
unsigned char rombank;
162
bool enableRam;
163
bool rombank0Mode;
164
165
static unsigned adjustedRombank(unsigned bank) { return bank & 0x1F ? bank : bank | 1; }
166
167
void setRombank() const {
168
if (rombank0Mode) {
169
const unsigned rb = toMulti64Rombank(rombank);
170
memptrs.setRombank0(rb & 0x30);
171
memptrs.setRombank(adjustedRombank(rb));
172
} else {
173
memptrs.setRombank0(0);
174
memptrs.setRombank(adjustedRombank(rombank & (rombanks(memptrs) - 1)));
175
}
176
}
177
178
public:
179
explicit Mbc1Multi64(MemPtrs &memptrs)
180
: memptrs(memptrs),
181
rombank(1),
182
enableRam(false),
183
rombank0Mode(false)
184
{
185
}
186
187
virtual void romWrite(const unsigned P, const unsigned data) {
188
switch (P >> 13 & 3) {
189
case 0:
190
enableRam = (data & 0xF) == 0xA;
191
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
192
break;
193
case 1:
194
rombank = (rombank & 0x60) | (data & 0x1F);
195
memptrs.setRombank(adjustedRombank(rombank0Mode ? toMulti64Rombank(rombank) : rombank & (rombanks(memptrs) - 1)));
196
break;
197
case 2:
198
rombank = (data << 5 & 0x60) | (rombank & 0x1F);
199
setRombank();
200
break;
201
case 3:
202
rombank0Mode = data & 1;
203
setRombank();
204
break;
205
}
206
}
207
208
virtual void saveState(SaveState::Mem &ss) const {
209
ss.rombank = rombank;
210
ss.enableRam = enableRam;
211
ss.rambankMode = rombank0Mode;
212
}
213
214
virtual void loadState(const SaveState::Mem &ss) {
215
rombank = ss.rombank;
216
enableRam = ss.enableRam;
217
rombank0Mode = ss.rambankMode;
218
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
219
setRombank();
220
}
221
222
virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const {
223
return (addr < 0x4000) == ((bank & 0xF) == 0);
224
}
225
226
virtual void SyncState(NewState *ns, bool isReader)
227
{
228
NSS(rombank);
229
NSS(enableRam);
230
NSS(rombank0Mode);
231
}
232
};
233
234
class Mbc2 : public DefaultMbc {
235
MemPtrs &memptrs;
236
unsigned char rombank;
237
bool enableRam;
238
239
public:
240
explicit Mbc2(MemPtrs &memptrs)
241
: memptrs(memptrs),
242
rombank(1),
243
enableRam(false)
244
{
245
}
246
247
virtual void romWrite(const unsigned P, const unsigned data) {
248
switch (P & 0x6100) {
249
case 0x0000:
250
enableRam = (data & 0xF) == 0xA;
251
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
252
break;
253
case 0x2100:
254
rombank = data & 0xF;
255
memptrs.setRombank(rombank & (rombanks(memptrs) - 1));
256
break;
257
}
258
}
259
260
virtual void saveState(SaveState::Mem &ss) const {
261
ss.rombank = rombank;
262
ss.enableRam = enableRam;
263
}
264
265
virtual void loadState(const SaveState::Mem &ss) {
266
rombank = ss.rombank;
267
enableRam = ss.enableRam;
268
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
269
memptrs.setRombank(rombank & (rombanks(memptrs) - 1));
270
}
271
272
virtual void SyncState(NewState *ns, bool isReader)
273
{
274
NSS(rombank);
275
NSS(enableRam);
276
}
277
};
278
279
class Mbc3 : public DefaultMbc {
280
MemPtrs &memptrs;
281
Rtc *const rtc;
282
unsigned char rombank;
283
unsigned char rambank;
284
bool enableRam;
285
286
static unsigned adjustedRombank(unsigned bank) { return bank & 0x7F ? bank : bank | 1; }
287
void setRambank() const {
288
unsigned flags = enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0;
289
290
if (rtc) {
291
rtc->set(enableRam, rambank);
292
293
if (rtc->getActive())
294
flags |= MemPtrs::RTC_EN;
295
}
296
297
memptrs.setRambank(flags, rambank & (rambanks(memptrs) - 1));
298
}
299
// we adjust the rombank before masking with size? this seems correct, as how would the mbc
300
// know that high rom address outputs were not connected
301
void setRombank() const { memptrs.setRombank(adjustedRombank(rombank) & (rombanks(memptrs) - 1)); }
302
303
public:
304
Mbc3(MemPtrs &memptrs, Rtc *const rtc)
305
: memptrs(memptrs),
306
rtc(rtc),
307
rombank(1),
308
rambank(0),
309
enableRam(false)
310
{
311
}
312
313
virtual void romWrite(const unsigned P, const unsigned data) {
314
switch (P >> 13 & 3) {
315
case 0:
316
enableRam = (data & 0xF) == 0xA;
317
setRambank();
318
break;
319
case 1:
320
rombank = data & 0x7F;
321
setRombank();
322
break;
323
case 2:
324
rambank = data;
325
setRambank();
326
break;
327
case 3:
328
if (rtc)
329
rtc->latch(data);
330
331
break;
332
}
333
}
334
335
virtual void saveState(SaveState::Mem &ss) const {
336
ss.rombank = rombank;
337
ss.rambank = rambank;
338
ss.enableRam = enableRam;
339
}
340
341
virtual void loadState(const SaveState::Mem &ss) {
342
rombank = ss.rombank;
343
rambank = ss.rambank;
344
enableRam = ss.enableRam;
345
setRambank();
346
setRombank();
347
}
348
349
virtual void SyncState(NewState *ns, bool isReader)
350
{
351
NSS(rombank);
352
NSS(rambank);
353
NSS(enableRam);
354
}
355
};
356
357
class HuC1 : public DefaultMbc {
358
MemPtrs &memptrs;
359
unsigned char rombank;
360
unsigned char rambank;
361
bool enableRam;
362
bool rambankMode;
363
364
void setRambank() const {
365
memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : MemPtrs::READ_EN,
366
rambankMode ? rambank & (rambanks(memptrs) - 1) : 0);
367
}
368
369
void setRombank() const { memptrs.setRombank((rambankMode ? rombank : rambank << 6 | rombank) & (rombanks(memptrs) - 1)); }
370
371
public:
372
explicit HuC1(MemPtrs &memptrs)
373
: memptrs(memptrs),
374
rombank(1),
375
rambank(0),
376
enableRam(false),
377
rambankMode(false)
378
{
379
}
380
381
virtual void romWrite(const unsigned P, const unsigned data) {
382
switch (P >> 13 & 3) {
383
case 0:
384
enableRam = (data & 0xF) == 0xA;
385
setRambank();
386
break;
387
case 1:
388
rombank = data & 0x3F;
389
setRombank();
390
break;
391
case 2:
392
rambank = data & 3;
393
rambankMode ? setRambank() : setRombank();
394
break;
395
case 3:
396
rambankMode = data & 1;
397
setRambank();
398
setRombank();
399
break;
400
}
401
}
402
403
virtual void saveState(SaveState::Mem &ss) const {
404
ss.rombank = rombank;
405
ss.rambank = rambank;
406
ss.enableRam = enableRam;
407
ss.rambankMode = rambankMode;
408
}
409
410
virtual void loadState(const SaveState::Mem &ss) {
411
rombank = ss.rombank;
412
rambank = ss.rambank;
413
enableRam = ss.enableRam;
414
rambankMode = ss.rambankMode;
415
setRambank();
416
setRombank();
417
}
418
419
virtual void SyncState(NewState *ns, bool isReader)
420
{
421
NSS(rombank);
422
NSS(rambank);
423
NSS(enableRam);
424
NSS(rambankMode);
425
}
426
};
427
428
class Mbc5 : public DefaultMbc {
429
MemPtrs &memptrs;
430
unsigned short rombank;
431
unsigned char rambank;
432
bool enableRam;
433
434
static unsigned adjustedRombank(const unsigned bank) { return bank; }
435
void setRambank() const { memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, rambank & (rambanks(memptrs) - 1)); }
436
void setRombank() const { memptrs.setRombank(adjustedRombank(rombank & (rombanks(memptrs) - 1))); }
437
438
public:
439
explicit Mbc5(MemPtrs &memptrs)
440
: memptrs(memptrs),
441
rombank(1),
442
rambank(0),
443
enableRam(false)
444
{
445
}
446
447
virtual void romWrite(const unsigned P, const unsigned data) {
448
switch (P >> 13 & 3) {
449
case 0:
450
enableRam = (data & 0xF) == 0xA;
451
setRambank();
452
break;
453
case 1:
454
rombank = P < 0x3000 ? (rombank & 0x100) | data
455
: (data << 8 & 0x100) | (rombank & 0xFF);
456
setRombank();
457
break;
458
case 2:
459
rambank = data & 0xF;
460
setRambank();
461
break;
462
case 3:
463
break;
464
}
465
}
466
467
virtual void saveState(SaveState::Mem &ss) const {
468
ss.rombank = rombank;
469
ss.rambank = rambank;
470
ss.enableRam = enableRam;
471
}
472
473
virtual void loadState(const SaveState::Mem &ss) {
474
rombank = ss.rombank;
475
rambank = ss.rambank;
476
enableRam = ss.enableRam;
477
setRambank();
478
setRombank();
479
}
480
481
virtual void SyncState(NewState *ns, bool isReader)
482
{
483
NSS(rombank);
484
NSS(rambank);
485
NSS(enableRam);
486
}
487
};
488
489
static bool hasRtc(const unsigned headerByte0x147) {
490
switch (headerByte0x147) {
491
case 0x0F:
492
case 0x10: return true;
493
default: return false;
494
}
495
}
496
497
}
498
499
void Cartridge::setStatePtrs(SaveState &state) {
500
state.mem.vram.set(memptrs.vramdata(), memptrs.vramdataend() - memptrs.vramdata());
501
state.mem.sram.set(memptrs.rambankdata(), memptrs.rambankdataend() - memptrs.rambankdata());
502
state.mem.wram.set(memptrs.wramdata(0), memptrs.wramdataend() - memptrs.wramdata(0));
503
}
504
505
void Cartridge::loadState(const SaveState &state) {
506
rtc.loadState(state);
507
mbc->loadState(state.mem);
508
}
509
510
static void enforce8bit(unsigned char *data, unsigned long sz) {
511
if (static_cast<unsigned char>(0x100))
512
while (sz--)
513
*data++ &= 0xFF;
514
}
515
516
static unsigned pow2ceil(unsigned n) {
517
--n;
518
n |= n >> 1;
519
n |= n >> 2;
520
n |= n >> 4;
521
n |= n >> 8;
522
++n;
523
524
return n;
525
}
526
527
int Cartridge::loadROM(const char *romfiledata, unsigned romfilelength, const bool forceDmg, const bool multicartCompat) {
528
//const std::auto_ptr<File> rom(newFileInstance(romfile));
529
530
//if (rom->fail())
531
// return -1;
532
533
unsigned rambanks = 1;
534
unsigned rombanks = 2;
535
bool cgb = false;
536
enum Cartridgetype { PLAIN, MBC1, MBC2, MBC3, MBC5, HUC1 } type = PLAIN;
537
538
{
539
unsigned char header[0x150];
540
//rom->read(reinterpret_cast<char*>(header), sizeof header);
541
if (romfilelength >= sizeof header)
542
std::memcpy(header, romfiledata, sizeof header);
543
else
544
return -1;
545
546
switch (header[0x0147]) {
547
case 0x00: std::puts("Plain ROM loaded."); type = PLAIN; break;
548
case 0x01: std::puts("MBC1 ROM loaded."); type = MBC1; break;
549
case 0x02: std::puts("MBC1 ROM+RAM loaded."); type = MBC1; break;
550
case 0x03: std::puts("MBC1 ROM+RAM+BATTERY loaded."); type = MBC1; break;
551
case 0x05: std::puts("MBC2 ROM loaded."); type = MBC2; break;
552
case 0x06: std::puts("MBC2 ROM+BATTERY loaded."); type = MBC2; break;
553
case 0x08: std::puts("Plain ROM with additional RAM loaded."); type = PLAIN; break;
554
case 0x09: std::puts("Plain ROM with additional RAM and Battery loaded."); type = PLAIN; break;
555
case 0x0B: std::puts("MM01 ROM not supported."); return -1;
556
case 0x0C: std::puts("MM01 ROM not supported."); return -1;
557
case 0x0D: std::puts("MM01 ROM not supported."); return -1;
558
case 0x0F: std::puts("MBC3 ROM+TIMER+BATTERY loaded."); type = MBC3; break;
559
case 0x10: std::puts("MBC3 ROM+TIMER+RAM+BATTERY loaded."); type = MBC3; break;
560
case 0x11: std::puts("MBC3 ROM loaded."); type = MBC3; break;
561
case 0x12: std::puts("MBC3 ROM+RAM loaded."); type = MBC3; break;
562
case 0x13: std::puts("MBC3 ROM+RAM+BATTERY loaded."); type = MBC3; break;
563
case 0x15: std::puts("MBC4 ROM not supported."); return -1;
564
case 0x16: std::puts("MBC4 ROM not supported."); return -1;
565
case 0x17: std::puts("MBC4 ROM not supported."); return -1;
566
case 0x19: std::puts("MBC5 ROM loaded."); type = MBC5; break;
567
case 0x1A: std::puts("MBC5 ROM+RAM loaded."); type = MBC5; break;
568
case 0x1B: std::puts("MBC5 ROM+RAM+BATTERY loaded."); type = MBC5; break;
569
case 0x1C: std::puts("MBC5+RUMBLE ROM not supported."); type = MBC5; break;
570
case 0x1D: std::puts("MBC5+RUMBLE+RAM ROM not suported."); type = MBC5; break;
571
case 0x1E: std::puts("MBC5+RUMBLE+RAM+BATTERY ROM not supported."); type = MBC5; break;
572
case 0xFC: std::puts("Pocket Camera ROM not supported."); return -1;
573
case 0xFD: std::puts("Bandai TAMA5 ROM not supported."); return -1;
574
case 0xFE: std::puts("HuC3 ROM not supported."); return -1;
575
case 0xFF: std::puts("HuC1 ROM+RAM+BATTERY loaded."); type = HUC1; break;
576
default: std::puts("Wrong data-format, corrupt or unsupported ROM."); return -1;
577
}
578
579
/*switch (header[0x0148]) {
580
case 0x00: rombanks = 2; break;
581
case 0x01: rombanks = 4; break;
582
case 0x02: rombanks = 8; break;
583
case 0x03: rombanks = 16; break;
584
case 0x04: rombanks = 32; break;
585
case 0x05: rombanks = 64; break;
586
case 0x06: rombanks = 128; break;
587
case 0x07: rombanks = 256; break;
588
case 0x08: rombanks = 512; break;
589
case 0x52: rombanks = 72; break;
590
case 0x53: rombanks = 80; break;
591
case 0x54: rombanks = 96; break;
592
default: return -1;
593
}
594
595
std::printf("rombanks: %u\n", rombanks);*/
596
597
switch (header[0x0149]) {
598
case 0x00: /*std::puts("No RAM");*/ rambanks = type == MBC2; break;
599
case 0x01: /*std::puts("2kB RAM");*/ /*rambankrom=1; break;*/
600
case 0x02: /*std::puts("8kB RAM");*/
601
rambanks = 1;
602
break;
603
case 0x03: /*std::puts("32kB RAM");*/
604
rambanks = 4;
605
break;
606
case 0x04: /*std::puts("128kB RAM");*/
607
rambanks = 16;
608
break;
609
case 0x05: /*std::puts("undocumented kB RAM");*/
610
rambanks = 16;
611
break;
612
default: /*std::puts("Wrong data-format, corrupt or unsupported ROM loaded.");*/
613
rambanks = 16;
614
break;
615
}
616
617
cgb = header[0x0143] >> 7 & (1 ^ forceDmg);
618
std::printf("cgb: %d\n", cgb);
619
}
620
621
std::printf("rambanks: %u\n", rambanks);
622
623
const std::size_t filesize = romfilelength; //rom->size();
624
rombanks = std::max(pow2ceil(filesize / 0x4000), 2u);
625
std::printf("rombanks: %u\n", static_cast<unsigned>(filesize / 0x4000));
626
627
mbc.reset();
628
memptrs.reset(rombanks, rambanks, cgb ? 8 : 2);
629
rtc.set(false, 0);
630
631
//rom->rewind();
632
//rom->read(reinterpret_cast<char*>(memptrs.romdata()), (filesize / 0x4000) * 0x4000ul);
633
std::memcpy(memptrs.romdata(), romfiledata, (filesize / 0x4000) * 0x4000ul);
634
std::memset(memptrs.romdata() + (filesize / 0x4000) * 0x4000ul, 0xFF, (rombanks - filesize / 0x4000) * 0x4000ul);
635
enforce8bit(memptrs.romdata(), rombanks * 0x4000ul);
636
637
//if (rom->fail())
638
// return -1;
639
640
switch (type) {
641
case PLAIN: mbc.reset(new Mbc0(memptrs)); break;
642
case MBC1:
643
if (!rambanks && rombanks == 64 && multicartCompat) {
644
std::puts("Multi-ROM \"MBC1\" presumed");
645
mbc.reset(new Mbc1Multi64(memptrs));
646
} else
647
mbc.reset(new Mbc1(memptrs));
648
649
break;
650
case MBC2: mbc.reset(new Mbc2(memptrs)); break;
651
case MBC3: mbc.reset(new Mbc3(memptrs, hasRtc(memptrs.romdata()[0x147]) ? &rtc : 0)); break;
652
case MBC5: mbc.reset(new Mbc5(memptrs)); break;
653
case HUC1: mbc.reset(new HuC1(memptrs)); break;
654
}
655
656
return 0;
657
}
658
659
static bool hasBattery(const unsigned char headerByte0x147) {
660
switch (headerByte0x147) {
661
case 0x03:
662
case 0x06:
663
case 0x09:
664
case 0x0F:
665
case 0x10:
666
case 0x13:
667
case 0x1B:
668
case 0x1E:
669
case 0xFF: return true;
670
default: return false;
671
}
672
}
673
674
void Cartridge::loadSavedata(const char *data) {
675
if (hasBattery(memptrs.romdata()[0x147])) {
676
int length = memptrs.rambankdataend() - memptrs.rambankdata();
677
std::memcpy(memptrs.rambankdata(), data, length);
678
data += length;
679
enforce8bit(memptrs.rambankdata(), length);
680
}
681
682
if (hasRtc(memptrs.romdata()[0x147])) {
683
unsigned long basetime;
684
std::memcpy(&basetime, data, 4);
685
rtc.setBaseTime(basetime);
686
}
687
}
688
689
int Cartridge::saveSavedataLength() {
690
int ret = 0;
691
if (hasBattery(memptrs.romdata()[0x147])) {
692
ret = memptrs.rambankdataend() - memptrs.rambankdata();
693
}
694
if (hasRtc(memptrs.romdata()[0x147])) {
695
ret += 4;
696
}
697
return ret;
698
}
699
700
void Cartridge::saveSavedata(char *dest) {
701
if (hasBattery(memptrs.romdata()[0x147])) {
702
int length = memptrs.rambankdataend() - memptrs.rambankdata();
703
std::memcpy(dest, memptrs.rambankdata(), length);
704
dest += length;
705
}
706
707
if (hasRtc(memptrs.romdata()[0x147])) {
708
const unsigned long basetime = rtc.getBaseTime();
709
std::memcpy(dest, &basetime, 4);
710
}
711
}
712
713
bool Cartridge::getMemoryArea(int which, unsigned char **data, int *length) const {
714
if (!data || !length)
715
return false;
716
717
switch (which)
718
{
719
case 0:
720
*data = memptrs.vramdata();
721
*length = memptrs.vramdataend() - memptrs.vramdata();
722
return true;
723
case 1:
724
*data = memptrs.romdata();
725
*length = memptrs.romdataend() - memptrs.romdata();
726
return true;
727
case 2:
728
*data = memptrs.wramdata(0);
729
*length = memptrs.wramdataend() - memptrs.wramdata(0);
730
return true;
731
case 3:
732
*data = memptrs.rambankdata();
733
*length = memptrs.rambankdataend() - memptrs.rambankdata();
734
return true;
735
736
default:
737
return false;
738
}
739
return false;
740
}
741
742
SYNCFUNC(Cartridge)
743
{
744
SSS(memptrs);
745
SSS(rtc);
746
TSS(mbc);
747
}
748
749
}
750
751