Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmeteor/source/memory.cpp
2 views
1
// Meteor - A Nintendo Gameboy Advance emulator
2
// Copyright (C) 2009-2011 Philippe Daouadi
3
//
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
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 for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17
#include "ameteor/memory.hpp"
18
#include "ameteor/io.hpp"
19
#include "ameteor/eeprom.hpp"
20
#include "ameteor/flash.hpp"
21
#include "ameteor/sram.hpp"
22
#include "globals.hpp"
23
#include "ameteor.hpp"
24
25
#include "debug.hpp"
26
27
#include <cstring>
28
#include <fstream>
29
#include <sstream>
30
#include <sys/types.h>
31
#include <sys/stat.h>
32
#include <fcntl.h>
33
#include <cerrno>
34
35
#define RET_ADD(mem, low, high, size) \
36
if (add >= low && (add+size) <= high) \
37
{ \
38
return mem + (add - low); \
39
}
40
41
#define debugm debug
42
43
namespace AMeteor
44
{
45
Memory::Memory () :
46
m_brom(NULL),
47
m_carttype(CTYPE_UNKNOWN),
48
m_cart(NULL)
49
{
50
m_wbram = new uint8_t[0x00040000];
51
m_wcram = new uint8_t[0x00008000];
52
m_pram = new uint8_t[0x00000400];
53
m_vram = new uint8_t[0x00018000];
54
m_oram = new uint8_t[0x00000400];
55
m_rom = new uint8_t[0x02000000];
56
57
Reset();
58
}
59
60
Memory::~Memory ()
61
{
62
if (m_brom)
63
delete [] m_brom;
64
delete [] m_wbram;
65
delete [] m_wcram;
66
delete [] m_pram;
67
delete [] m_vram;
68
delete [] m_oram;
69
delete [] m_rom;
70
if (m_cart)
71
delete m_cart;
72
}
73
74
void Memory::SetCartTypeFromSize (uint32_t size)
75
{
76
switch (size)
77
{
78
case 0x0200:
79
SetCartType(CTYPE_EEPROM512);
80
break;
81
case 0x2000:
82
SetCartType(CTYPE_EEPROM8192);
83
break;
84
case 0x8000:
85
SetCartType(CTYPE_SRAM);
86
break;
87
case 0x10000:
88
SetCartType(CTYPE_FLASH64);
89
break;
90
case 0x20000:
91
SetCartType(CTYPE_FLASH128);
92
break;
93
default:
94
met_abort("Unknown cartridge memory size");
95
break;
96
}
97
}
98
99
void Memory::DeleteCart()
100
{
101
if (m_cart)
102
delete m_cart;
103
m_cart = NULL;
104
print_bizhawk("Cart Memory unloaded.\n");
105
}
106
107
void Memory::SetCartType (uint8_t type)
108
{
109
if (m_cart)
110
{
111
delete m_cart;
112
print_bizhawk("Cart Memory unloaded.\n");
113
m_cart = NULL;
114
}
115
switch (type)
116
{
117
case CTYPE_UNKNOWN:
118
m_cart = NULL;
119
print_bizhawk("Cart Memory set to <empty>.\n");
120
break;
121
case CTYPE_FLASH64:
122
m_cart = new Flash(false);
123
print_bizhawk("Cart Memory set to FLASH64\n");
124
break;
125
case CTYPE_FLASH128:
126
m_cart = new Flash(true);
127
print_bizhawk("Cart Memory set to FLASH128\n");
128
break;
129
case CTYPE_EEPROM512:
130
m_cart = new Eeprom(false);
131
print_bizhawk("Cart Memory set to EEPROM512\n");
132
break;
133
case CTYPE_EEPROM8192:
134
m_cart = new Eeprom(true);
135
print_bizhawk("Cart Memory set to EEPROM8192\n");
136
break;
137
case CTYPE_SRAM:
138
m_cart = new Sram();
139
print_bizhawk("Cart Memory set to SRAM\n");
140
break;
141
default:
142
met_abort("Unknown cartridge memory type");
143
print_bizhawk("Problem setting Cart Memory. This is bad.\n");
144
break;
145
}
146
m_carttype = type;
147
}
148
149
void Memory::Reset (uint32_t params)
150
{
151
static const uint8_t InitMemoryTime[0xF] = {
152
1, // 00 - BIOS
153
0, // 01 - Not used
154
3, // 02 - Work RAM 256K
155
1, // 03 - Work RAM 32K
156
1, // 04 - I/O Registers
157
1, // 05 - Palette RAM
158
1, // 06 - VRAM
159
1, // 07 - OAM
160
5, // 08 - ROM, Wait0
161
5, // 09 - ROM, Wait0
162
5, // 0A - ROM, Wait1
163
5, // 0B - ROM, Wait1
164
5, // 0C - ROM, Wait2
165
5, // 0D - ROM, Wait2
166
5 // 0E - SRAM
167
};
168
169
static const uint8_t InitMemoryTimeSeq[0x3] = {
170
3, // 08-09 - ROM, Wait0
171
5, // 0A-0B - ROM, Wait1
172
9 // 0C-0D - ROM, Wait2
173
};
174
175
if (m_brom && (params & UNIT_MEMORY_BIOS))
176
{
177
delete [] m_brom;
178
m_brom = NULL;
179
}
180
std::memcpy(m_memtime, InitMemoryTime, sizeof(m_memtime));
181
std::memcpy(m_memtimeseq, InitMemoryTimeSeq, sizeof(m_memtimeseq));
182
std::memset(m_wbram, 0, 0x00040000);
183
std::memset(m_wcram, 0, 0x00008000);
184
std::memset(m_pram , 0, 0x00000400);
185
std::memset(m_vram , 0, 0x00018000);
186
std::memset(m_oram , 0, 0x00000400);
187
if (params & UNIT_MEMORY_ROM)
188
std::memset(m_rom , 0, 0x02000000);
189
SetCartType(CTYPE_UNKNOWN);
190
//m_cartfile.clear();
191
}
192
193
void Memory::ClearWbram ()
194
{
195
std::memset(m_wbram, 0, 0x00040000);
196
}
197
198
void Memory::ClearWcram ()
199
{
200
std::memset(m_wcram, 0, 0x00008000);
201
}
202
203
void Memory::ClearPalette ()
204
{
205
std::memset(m_pram , 0, 0x00000400);
206
}
207
208
void Memory::ClearVram ()
209
{
210
std::memset(m_vram , 0, 0x00018000);
211
}
212
213
void Memory::ClearOam ()
214
{
215
std::memset(m_oram , 0, 0x00000400);
216
LCD.OamWrite(0x07000000, 0x07000400);
217
}
218
219
void Memory::SoftReset ()
220
{
221
std::memset(m_wcram+0x7E00, 0, 0x200);
222
}
223
224
void Memory::TimeEvent ()
225
{
226
/*
227
if (!m_cartfile.empty())
228
{
229
// FIXME, this may fail, we should do something to inform user
230
std::ofstream f(m_cartfile.c_str());
231
m_cart->Save(f);
232
}
233
CLOCK.DisableBattery();
234
*/
235
}
236
237
bool Memory::LoadBios (const char* filename)
238
{
239
std::ifstream file(filename);
240
if (!m_brom)
241
m_brom = new uint8_t[0x00004000];
242
memset(m_brom, 0, 0x00004000);
243
file.read((char*)m_brom, 0x00004000);
244
if (file.fail())
245
return false;
246
return true;
247
}
248
249
void Memory::LoadBios (const uint8_t* data, uint32_t size)
250
{
251
if (!m_brom)
252
m_brom = new uint8_t[0x00004000];
253
uint32_t until = std::min(size, 0x00004000u);
254
std::memcpy(m_brom, data, until);
255
std::memset(m_brom+until, 0, 0x00004000-until);
256
}
257
258
bool Memory::LoadRom (const char* filename)
259
{
260
std::ifstream file(filename);
261
std::memset(m_rom, 0, 0x02000000);
262
file.read((char*)m_rom, 0x02000000);
263
if (file.bad())
264
return false;
265
return true;
266
}
267
268
void Memory::LoadRom (const uint8_t* data, uint32_t size)
269
{
270
uint32_t until = std::min(size, 0x02000000u);
271
std::memcpy(m_rom, data, until);
272
std::memset(m_rom+until, 0, 0x02000000-until);
273
}
274
275
bool Memory::LoadCart(const uint8_t* data, uint32_t size)
276
{
277
SetCartTypeFromSize(size);
278
if (!m_cart)
279
return false;
280
std::stringstream ss = std::stringstream(std::string((const char*)data, size), std::ios_base::in | std::ios_base::binary);
281
return m_cart->Load(ss);
282
}
283
284
bool Memory::SaveCart(uint8_t** data, uint32_t* size)
285
{
286
if (!m_cart)
287
return false;
288
if (!data || !size)
289
return false;
290
std::stringstream ss = std::stringstream(std::ios_base::out | std::ios_base::binary);
291
if (!m_cart->Save(ss))
292
return false;
293
std::string s = ss.str();
294
uint8_t *ret = (uint8_t *)std::malloc(s.length());
295
std::memcpy(ret, s.data(), s.length());
296
*data = ret;
297
*size = s.length();
298
return true;
299
}
300
301
void Memory::SaveCartDestroy(uint8_t* data)
302
{
303
std::free(data);
304
}
305
306
/*
307
Memory::CartError Memory::LoadCart ()
308
{
309
struct stat buf;
310
if (stat(m_cartfile.c_str(), &buf) == -1)
311
return errno == ENOENT ? CERR_NOT_FOUND : CERR_FAIL;
312
SetCartTypeFromSize(buf.st_size);
313
std::ifstream f(m_cartfile.c_str());
314
if (!m_cart->Load(f))
315
return CERR_FAIL;
316
return CERR_NO_ERROR;
317
}
318
*/
319
320
#ifdef __LIBRETRO__
321
bool Memory::LoadCartInferred ()
322
{
323
uint32_t size = *(uint32_t*)(CartMemData+CartMem::MAX_SIZE);
324
if (!size)
325
return false;
326
SetCartTypeFromSize(size);
327
std::istringstream ss;
328
ss.str(std::string((char*)CartMemData, CartMem::MAX_SIZE));
329
if (!m_cart->Load(ss))
330
return false;
331
return true;
332
}
333
#endif
334
335
#if 0
336
uint8_t* Memory::GetRealAddress (uint32_t add, uint8_t size)
337
{
338
RET_ADD(m_brom , 0x00000000u, 0x00004000u, size);
339
RET_ADD(m_wbram, 0x02000000u, 0x02040000u, size);
340
RET_ADD(m_wbram, 0x02040000u, 0x02080000u, size); // mirror
341
RET_ADD(m_wcram, 0x03000000u, 0x03008000u, size);
342
RET_ADD(m_wcram, 0x03008000u, 0x03010000u, size); // mirror
343
RET_ADD(m_wcram, 0x03010000u, 0x03018000u, size); // mirror
344
RET_ADD(m_wcram, 0x03FF8000u, 0x04000000u, size); // mirror
345
RET_ADD(m_pram , 0x05000000u, 0x05000400u, size);
346
RET_ADD(m_vram , 0x06000000u, 0x06018000u, size);
347
RET_ADD(m_oram , 0x07000000u, 0x07000400u, size);
348
RET_ADD(m_oram , 0x07000400u, 0x07000800u, size);
349
RET_ADD(m_rom , 0x08000000u, 0x0A000000u, size);
350
RET_ADD(m_rom , 0x0A000000u, 0x0C000000u, size);
351
RET_ADD(m_rom , 0x0C000000u, 0x0E000000u, size);
352
RET_ADD(m_sram , 0x0E000000u, 0x0E010000u, size);
353
354
return NULL;
355
}
356
#else
357
uint8_t* Memory::GetRealAddress (uint32_t add, uint8_t MET_UNUSED(size))
358
{
359
uint32_t loadd = add & 0x00FFFFFF;
360
switch (add >> 24)
361
{
362
case 0x0:
363
if (m_brom)
364
return m_brom+(loadd & 0x3FFF);
365
else
366
return NULL;
367
case 0x2:
368
return m_wbram+(loadd & 0x3FFFF);
369
case 0x3:
370
return m_wcram+(loadd & 0x7FFF);
371
case 0x5:
372
return m_pram+(loadd & 0x3FF);
373
case 0x6:
374
// we have 64K+32K+(32K mirror) and this whole thing is mirrored
375
// TODO : can't we simplify this with an AND ?
376
if ((loadd % 0x20000) > 0x18000)
377
loadd -= 0x8000;
378
return m_vram+(loadd & 0x1FFFF);
379
case 0x7:
380
return m_oram+(loadd & 0x3FF);
381
case 0x8:
382
return m_rom+loadd;
383
case 0x9:
384
return m_rom+0x01000000+loadd;
385
case 0xA:
386
return m_rom+loadd;
387
case 0xB:
388
return m_rom+0x01000000+loadd;
389
case 0xC:
390
return m_rom+loadd;
391
case 0xD:
392
return m_rom+0x01000000+loadd;
393
default:
394
return NULL;
395
}
396
}
397
#endif
398
399
void Memory::UpdateWaitStates (uint16_t waitcnt)
400
{
401
static const uint8_t GamePakTimeFirstAccess[] = { 5, 4, 3, 9 };
402
403
// SRAM
404
m_memtime[0xE] = GamePakTimeFirstAccess[waitcnt & 0x3];
405
406
// Second access
407
if (waitcnt & (0x1 << 4))
408
m_memtimeseq[0] = 2;
409
else
410
m_memtimeseq[0] = 3;
411
if (waitcnt & (0x1 << 7))
412
m_memtimeseq[1] = 2;
413
else
414
m_memtimeseq[1] = 5;
415
if (waitcnt & (0x1 << 10))
416
m_memtimeseq[2] = 2;
417
else
418
m_memtimeseq[2] = 9;
419
420
// First access
421
m_memtime[0x8] = m_memtime[0x9] =
422
GamePakTimeFirstAccess[(waitcnt >> 2) & 0x3];
423
m_memtime[0xA] = m_memtime[0xB] =
424
GamePakTimeFirstAccess[(waitcnt >> 5) & 0x3];
425
m_memtime[0xC] = m_memtime[0xD] =
426
GamePakTimeFirstAccess[(waitcnt >> 8) & 0x3];
427
}
428
429
uint8_t Memory::GetCycles16NoSeq (uint32_t add, uint32_t count)
430
{
431
add >>= 24;
432
switch (add)
433
{
434
case 0x00 :
435
case 0x03 :
436
case 0x04 :
437
case 0x07 :
438
// 32 bits bus
439
return m_memtime[add] * count;
440
case 0x08 :
441
case 0x09 :
442
case 0x0A :
443
case 0x0B :
444
case 0x0C :
445
case 0x0D :
446
// 16 bits bus
447
// sequencial and non sequencial reads don't take the same time
448
return m_memtime[add] + m_memtimeseq[(add-0x08) & 0xFE] * (count-1);
449
default :
450
// 16 bits bus (and 8 for SRAM, but only 8 bits accesses are
451
// authorized in this area, so we don't care about 16 and 32 bits
452
// accesses)
453
return m_memtime[add] * count;
454
}
455
}
456
457
uint8_t Memory::GetCycles16Seq (uint32_t add, uint32_t count)
458
{
459
add >>= 24;
460
switch (add)
461
{
462
case 0x00 :
463
case 0x03 :
464
case 0x04 :
465
case 0x07 :
466
return m_memtime[add] * count;
467
case 0x08 :
468
case 0x09 :
469
case 0x0A :
470
case 0x0B :
471
case 0x0C :
472
case 0x0D :
473
return m_memtimeseq[(add-0x08) & 0xFE] * count;
474
default :
475
return m_memtime[add] * count;
476
}
477
}
478
479
uint8_t Memory::GetCycles32NoSeq (uint32_t add, uint32_t count)
480
{
481
add >>= 24;
482
switch (add)
483
{
484
case 0x00 :
485
case 0x03 :
486
case 0x04 :
487
case 0x07 :
488
return m_memtime[add] * count;
489
case 0x08 :
490
case 0x09 :
491
case 0x0A :
492
case 0x0B :
493
case 0x0C :
494
case 0x0D :
495
return m_memtime[add] + m_memtimeseq[(add-0x08) & 0xFE] * (count*2-1);
496
default :
497
return m_memtime[add] * count * 2;
498
}
499
}
500
501
uint8_t Memory::GetCycles32Seq (uint32_t add, uint32_t count)
502
{
503
add >>= 24;
504
switch (add)
505
{
506
case 0x00 :
507
case 0x03 :
508
case 0x04 :
509
case 0x07 :
510
return m_memtime[add] * count;
511
case 0x08 :
512
case 0x09 :
513
case 0x0A :
514
case 0x0B :
515
case 0x0C :
516
case 0x0D :
517
return m_memtimeseq[(add-0x08) & 0xFE] * count * 2;
518
default :
519
return m_memtime[add] * count * 2;
520
}
521
}
522
523
bool Memory::SaveState (std::ostream& stream)
524
{
525
SS_WRITE_ARRAY(m_memtime);
526
SS_WRITE_ARRAY(m_memtimeseq);
527
// write if we have a custom bios and write it too
528
bool b = m_brom;
529
SS_WRITE_VAR(b);
530
if (b)
531
{
532
SS_WRITE_DATA(m_brom, 0x00004000);
533
}
534
SS_WRITE_DATA(m_wbram, 0x00040000);
535
SS_WRITE_DATA(m_wcram, 0x00008000);
536
SS_WRITE_DATA(m_pram , 0x00000400);
537
SS_WRITE_DATA(m_vram , 0x00018000);
538
SS_WRITE_DATA(m_oram , 0x00000400);
539
540
SS_WRITE_VAR(m_carttype);
541
542
if (m_cart)
543
if (!m_cart->SaveState(stream))
544
return false;
545
546
return true;
547
}
548
549
bool Memory::LoadState (std::istream& stream)
550
{
551
Reset(0);
552
553
SS_READ_ARRAY(m_memtime);
554
SS_READ_ARRAY(m_memtimeseq);
555
// read if we have a custom bios and write it too
556
bool b;
557
SS_READ_VAR(b);
558
if (b)
559
{
560
SS_READ_DATA(m_brom , 0x00004000);
561
}
562
else
563
{
564
UnloadBios();
565
}
566
SS_READ_DATA(m_wbram, 0x00040000);
567
SS_READ_DATA(m_wcram, 0x00008000);
568
SS_READ_DATA(m_pram , 0x00000400);
569
SS_READ_DATA(m_vram , 0x00018000);
570
SS_READ_DATA(m_oram , 0x00000400);
571
572
SS_READ_VAR(m_carttype);
573
574
this->SetCartType(m_carttype);
575
if (m_cart)
576
if (!m_cart->LoadState(stream))
577
return false;
578
579
return true;
580
}
581
582
////////////////////////////////////////////////////////////////////////////////
583
// Read
584
////////////////////////////////////////////////////////////////////////////////
585
586
uint8_t Memory::Peek8 (uint32_t add)
587
{
588
switch (add >> 24)
589
{
590
case 0x04:
591
if (add < 0x04001000)
592
return IO.DRead8(add & 0xfff);
593
else
594
return 0;
595
case 0x0e:
596
// todo: cart reading
597
return 0xff;
598
default:
599
uint8_t *r = (uint8_t*)GetRealAddress(add, 1);
600
return r ? *r : 0;
601
}
602
}
603
604
uint8_t Memory::Read8 (uint32_t add)
605
{
606
switch (add >> 24)
607
{
608
case 0x00:
609
if (R(15) < 0x01000000)
610
return m_brom[add & 0x3FFF];
611
else
612
return 0x0E;
613
case 0x04:
614
return IO.Read8(add);
615
case 0x0E:
616
return ReadCart(add);
617
default:
618
uint8_t *r = (uint8_t*)GetRealAddress(add, 1);
619
if (!r)
620
{
621
debugm("Unknown address for Read8 : " << IOS_ADD << add);
622
// FIXME : in arm state, vba returns read8(r15 + (add & 3))
623
// and in thumb read8(r15 + (add & 1))
624
return Read8(R(15));
625
}
626
return *r;
627
}
628
}
629
630
uint16_t Memory::Read16 (uint32_t add)
631
{
632
switch (add >> 24)
633
{
634
case 0x00:
635
if (R(15) < 0x01000000)
636
return *(uint16_t*)(m_brom+(add & 0x3FFE));
637
else
638
return 0xF00E;
639
case 0x04:
640
return IO.Read16(add);
641
case 0x0D:
642
if (m_carttype == CTYPE_EEPROM512 || m_carttype == CTYPE_EEPROM8192)
643
return static_cast<Eeprom*>(m_cart)->Read();
644
default:
645
uint16_t *r = (uint16_t*)GetRealAddress(add, 2);
646
if (!r)
647
{
648
debugm("Unknown address for Read16 : " << IOS_ADD << add);
649
if (R(15) == add)
650
met_abort("Illegal PC");
651
// FIXME : in arm state, vba returns read16(r15 + (add & 2))
652
return Read16(R(15));
653
}
654
return *r;
655
}
656
}
657
658
uint32_t Memory::Read32 (uint32_t add)
659
{
660
switch (add >> 24)
661
{
662
case 0x00:
663
if (R(15) < 0x01000000)
664
return *(uint32_t*)(m_brom+(add & 0x3FFC));
665
else
666
// TODO a better bios protection than this one (read8 and read16 too)
667
// this value corresponds to MOVS r15, r14
668
return 0xE1B0F00E;
669
case 0x04:
670
return IO.Read32(add);
671
default:
672
uint32_t *r = (uint32_t*)GetRealAddress(add, 4);
673
if (!r)
674
{
675
debugm("Unknown address for Read32 : " << IOS_ADD << add);
676
if (R(15) == add)
677
met_abort("Illegal PC");
678
if (FLAG_T)
679
{
680
uint16_t o = Read16(R(15));
681
return o | o << 16;
682
}
683
else
684
return Read32(R(15));
685
}
686
return *r;
687
}
688
}
689
690
uint8_t Memory::ReadCart (uint16_t add)
691
{
692
if (m_cart)
693
return m_cart->Read(add);
694
else
695
return 0;
696
}
697
698
////////////////////////////////////////////////////////////////////////////////
699
// Write
700
////////////////////////////////////////////////////////////////////////////////
701
702
void Memory::Write8 (uint32_t add, uint8_t val)
703
{
704
uint8_t baseadd = add >> 24;
705
switch (baseadd)
706
{
707
case 0x04:
708
IO.Write8(add, val);
709
break;
710
case 0x00:
711
case 0x08:
712
case 0x09:
713
case 0x0A:
714
case 0x0B:
715
case 0x0C:
716
case 0x0D:
717
debugm("Writing on read only memory");
718
break;
719
case 0x0E:
720
WriteCart(add & 0xFFFF, val);
721
break;
722
default:
723
uint8_t *r = (uint8_t*)GetRealAddress(add, 1);
724
if (!r)
725
{
726
debugm("Unknown address for Write8 : " << IOS_ADD << add);
727
}
728
else
729
{
730
*r = val;
731
if (baseadd == 5 || baseadd == 6)
732
r[1] = val;
733
else if (baseadd == 7)
734
met_abort("not implemented");
735
}
736
break;
737
}
738
}
739
740
void Memory::Write16 (uint32_t add, uint16_t val)
741
{
742
add &= 0xFFFFFFFE;
743
uint8_t baseadd = add >> 24;
744
switch (baseadd)
745
{
746
case 0x04:
747
IO.Write16(add, val);
748
break;
749
case 0x00:
750
case 0x08:
751
case 0x09:
752
case 0x0A:
753
case 0x0B:
754
case 0x0C:
755
case 0x0D:
756
debugm("Writing on read only memory");
757
break;
758
case 0x0E:
759
met_abort("Writing 16 bytes in SRAM/Flash");
760
break;
761
default:
762
uint16_t *r = (uint16_t*)GetRealAddress(add, 2);
763
if (!r)
764
{
765
debugm("Unknown address for Write16 : " << IOS_ADD << add);
766
}
767
else
768
{
769
*r = val;
770
if (!DMA.GraphicDma() && baseadd == 7)
771
LCD.OamWrite16((add & 0x3FF) | 0x07000000);
772
}
773
break;
774
}
775
}
776
777
void Memory::Write32 (uint32_t add, uint32_t val)
778
{
779
add &= 0xFFFFFFFC;
780
uint8_t baseadd = add >> 24;
781
switch (baseadd)
782
{
783
case 0x04:
784
IO.Write32(add, val);
785
break;
786
case 0x00:
787
case 0x08:
788
case 0x09:
789
case 0x0A:
790
case 0x0B:
791
case 0x0C:
792
case 0x0D:
793
debugm("Writing on read only memory");
794
break;
795
case 0x0E:
796
met_abort("Writing 32 bytes in SRAM/Flash");
797
break;
798
default:
799
uint32_t *r = (uint32_t*)GetRealAddress(add, 4);
800
if (!r)
801
{
802
debugm("Unknown address for Write32 : " << IOS_ADD << add);
803
}
804
else
805
{
806
*r = val;
807
if (!DMA.GraphicDma() && baseadd == 7)
808
LCD.OamWrite32((add & 0x3FF) | 0x07000000);
809
}
810
break;
811
}
812
}
813
814
void Memory::WriteEepromDma (uint32_t src, uint16_t size)
815
{
816
if (m_carttype == CTYPE_UNKNOWN)
817
{
818
if (size == 17 || size == 81)
819
SetCartType(CTYPE_EEPROM8192);
820
else if (size == 9 || size == 73)
821
SetCartType(CTYPE_EEPROM512);
822
else
823
met_abort("Unknown DMA3 size for EEPROM");
824
}
825
else if (m_carttype != CTYPE_EEPROM512 && m_carttype != CTYPE_EEPROM8192)
826
met_abort("EEPROM DMA3 on non EEPROM cartridge");
827
828
Eeprom* eeprom = static_cast<Eeprom*>(m_cart);
829
if (size == 17 || size == 81)
830
{
831
if (eeprom->GetSize() != 0x2000)
832
met_abort("DMA3 size not corresponding to EEPROM size");
833
}
834
else if (size == 9 || size == 73)
835
{
836
if (eeprom->GetSize() != 0x0200)
837
met_abort("DMA3 size not corresponding to EEPROM size");
838
}
839
else
840
met_abort("Unknown size for EEPROM DMA");
841
842
//if (eeprom->Write((uint16_t*)GetRealAddress(src), size))
843
// CLOCK.SetBattery(CART_SAVE_TIME);
844
eeprom->Write((uint16_t*)GetRealAddress(src), size);
845
}
846
847
#if 0
848
void Memory::ReadEepromDma (uint32_t dest, uint16_t size)
849
{
850
if (m_carttype != CTYPE_EEPROM)
851
met_abort("EEPROM DMA3 on non EEPROM or unknown cartridge");
852
if (size != 68)
853
met_abort("EEPROM DMA3 read with invalid size");
854
Eeprom* eeprom = static_cast<Eeprom*>(m_cart);
855
eeprom->Read((uint16_t*)GetRealAddress(dest));
856
}
857
#endif
858
859
#ifdef NO_MEMMEM // memmem() is a GNU extension, and does not exist in at least MinGW.
860
#define memmem memmem_compat
861
// Implementation from Git.
862
static void *memmem_compat(const void *haystack, size_t haystack_len,
863
const void *needle, size_t needle_len)
864
{
865
const char *begin = (const char*)haystack;
866
const char *last_possible = begin + haystack_len - needle_len;
867
868
if (needle_len == 0)
869
return (void *)begin;
870
871
if (haystack_len < needle_len)
872
return NULL;
873
874
for (; begin <= last_possible; begin++)
875
{
876
if (!memcmp(begin, needle, needle_len))
877
return (void *)begin;
878
}
879
880
return NULL;
881
}
882
#endif
883
884
void Memory::WriteCart (uint16_t add, uint8_t val)
885
{
886
if (m_carttype == CTYPE_EEPROM512 || m_carttype == CTYPE_EEPROM8192)
887
met_abort("Writing in SRAM/FLASH while using EEPROM");
888
if (!m_cart)
889
if (add == 0x5555)
890
{
891
if (memmem((char*)m_rom, 0x02000000, "FLASH1M_V", 9))
892
SetCartType(CTYPE_FLASH128);
893
else
894
SetCartType(CTYPE_FLASH64);
895
}
896
else
897
SetCartType(CTYPE_SRAM);
898
//if (m_cart->Write(add, val))
899
// CLOCK.SetBattery(CART_SAVE_TIME);
900
m_cart->Write(add, val);
901
}
902
903
uint8_t *Memory::GetMemoryArea(int which)
904
{
905
switch (which)
906
{
907
case 0:
908
return m_brom; // BIOS - System ROM
909
case 1:
910
return m_wbram; // WRAM - On-board Work RAM
911
case 2:
912
return m_wcram; // WRAM - In-chip Work RAM
913
case 3:
914
return m_pram; // BG/OBJ Palette RAM
915
case 4:
916
return m_vram; // VRAM - Video RAM
917
case 5:
918
return m_oram; // OAM - OBJ Attributes
919
case 6:
920
return m_rom; // Game Pake ROM/FlashROM (max 32MB)
921
default:
922
return 0;
923
}
924
}
925
}
926
927