Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
folium-app
GitHub Repository: folium-app/Folium
Path: blob/a-new-beginning/Cherry/Core/Memory.cpp
2 views
1
/*
2
* Gearcoleco - ColecoVision Emulator
3
* Copyright (C) 2021 Ignacio Sanchez
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 as published by
7
* the Free Software Foundation, either version 3 of the License, or
8
* any later version.
9
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
14
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see http://www.gnu.org/licenses/
17
*
18
*/
19
20
#include <iostream>
21
#include <iomanip>
22
#include <fstream>
23
#include "CVMemory.h"
24
#include "Processor.h"
25
#include "Cartridge.h"
26
#include "Mapper.h"
27
#include "StandardMapper.h"
28
#include "MegaCartMapper.h"
29
#include "ActivisionMapper.h"
30
#include "OCMMapper.h"
31
32
#include "CVMemory.h"
33
#include "Processor.h"
34
#include "Cartridge.h"
35
#include "common.h"
36
37
CVMemory::CVMemory(Cartridge* pCartridge)
38
{
39
m_pCartridge = pCartridge;
40
InitPointer(m_pProcessor);
41
InitPointer(m_pMapper);
42
InitPointer(m_pDisassembledRomMap);
43
InitPointer(m_pDisassembledRamMap);
44
InitPointer(m_pDisassembledBiosMap);
45
InitPointer(m_pDisassembledSGMRamMap);
46
InitPointer(m_pRunToBreakpoint);
47
InitPointer(m_pBios);
48
InitPointer(m_pRam);
49
InitPointer(m_pSGMRam);
50
m_bBiosLoaded = false;
51
m_bSGMUpper = false;
52
m_bSGMLower = false;
53
m_iTotalCycles = 0;
54
}
55
56
CVMemory::~CVMemory()
57
{
58
SafeDelete(m_pMapper);
59
SafeDeleteArray(m_pBios);
60
SafeDeleteArray(m_pRam);
61
SafeDeleteArray(m_pSGMRam);
62
63
if (IsValidPointer(m_pDisassembledRomMap))
64
{
65
for (int i = 0; i < MAX_ROM_SIZE; i++)
66
{
67
SafeDelete(m_pDisassembledRomMap[i]);
68
}
69
SafeDeleteArray(m_pDisassembledRomMap);
70
}
71
72
if (IsValidPointer(m_pDisassembledRamMap))
73
{
74
for (int i = 0; i < 0x400; i++)
75
{
76
SafeDelete(m_pDisassembledRamMap[i]);
77
}
78
SafeDeleteArray(m_pDisassembledRamMap);
79
}
80
81
if (IsValidPointer(m_pDisassembledBiosMap))
82
{
83
for (int i = 0; i < 0x2000; i++)
84
{
85
SafeDelete(m_pDisassembledBiosMap[i]);
86
}
87
SafeDeleteArray(m_pDisassembledBiosMap);
88
}
89
90
if (IsValidPointer(m_pDisassembledSGMRamMap))
91
{
92
for (int i = 0; i < 0x8000; i++)
93
{
94
SafeDelete(m_pDisassembledSGMRamMap[i]);
95
}
96
SafeDeleteArray(m_pDisassembledSGMRamMap);
97
}
98
}
99
100
void CVMemory::SetProcessor(Processor* pProcessor)
101
{
102
m_pProcessor = pProcessor;
103
}
104
105
void CVMemory::Init()
106
{
107
m_pRam = new u8[0x0400];
108
m_pBios = new u8[0x2000];
109
m_pSGMRam = new u8[0x8000];
110
111
#ifndef GEARCOLECO_DISABLE_DISASSEMBLER
112
m_pDisassembledRomMap = new stDisassembleRecord*[MAX_ROM_SIZE];
113
for (int i = 0; i < MAX_ROM_SIZE; i++)
114
{
115
InitPointer(m_pDisassembledRomMap[i]);
116
}
117
118
m_pDisassembledRamMap = new stDisassembleRecord*[0x400];
119
for (int i = 0; i < 0x400; i++)
120
{
121
InitPointer(m_pDisassembledRamMap[i]);
122
}
123
124
m_pDisassembledBiosMap = new stDisassembleRecord*[0x2000];
125
for (int i = 0; i < 0x2000; i++)
126
{
127
InitPointer(m_pDisassembledBiosMap[i]);
128
}
129
130
m_pDisassembledSGMRamMap = new stDisassembleRecord*[0x8000];
131
for (int i = 0; i < 0x8000; i++)
132
{
133
InitPointer(m_pDisassembledSGMRamMap[i]);
134
}
135
#endif
136
137
m_BreakpointsCPU.clear();
138
m_BreakpointsMem.clear();
139
140
InitPointer(m_pRunToBreakpoint);
141
142
Reset();
143
}
144
145
void CVMemory::SetupMapper()
146
{
147
SafeDelete(m_pMapper);
148
149
switch (m_pCartridge->GetType())
150
{
151
case Cartridge::CartridgeMegaCart:
152
m_pMapper = new MegaCartMapper(m_pCartridge);
153
break;
154
case Cartridge::CartridgeActivisionCart:
155
m_pMapper = new ActivisionMapper(m_pCartridge);
156
break;
157
case Cartridge::CartridgeOCM:
158
m_pMapper = new OCMMapper(m_pCartridge, this);
159
break;
160
default:
161
m_pMapper = new StandardMapper(m_pCartridge);
162
break;
163
}
164
165
m_pMapper->Reset();
166
}
167
168
void CVMemory::Reset()
169
{
170
m_iTotalCycles = 0;
171
m_bSGMUpper = false;
172
m_bSGMLower = false;
173
174
for (int i = 0; i < 0x400; i++)
175
{
176
m_pRam[i] = rand() % 256;
177
}
178
179
for (int i = 0; i < 0x8000; i++)
180
{
181
m_pSGMRam[i] = rand() % 256;
182
}
183
184
if (m_pCartridge->IsPAL())
185
m_pBios[0x69] = 0x32;
186
else
187
m_pBios[0x69] = 0x3C;
188
}
189
190
void CVMemory::SaveState(std::ostream& stream)
191
{
192
stream.write(reinterpret_cast<const char*> (m_pRam), 0x400);
193
stream.write(reinterpret_cast<const char*> (m_pSGMRam), 0x8000);
194
stream.write(reinterpret_cast<const char*> (&m_bSGMUpper), sizeof(m_bSGMUpper));
195
stream.write(reinterpret_cast<const char*> (&m_bSGMLower), sizeof(m_bSGMLower));
196
m_pMapper->SaveState(stream);
197
}
198
199
void CVMemory::LoadState(std::istream& stream)
200
{
201
stream.read(reinterpret_cast<char*> (m_pRam), 0x400);
202
stream.read(reinterpret_cast<char*> (m_pSGMRam), 0x8000);
203
stream.read(reinterpret_cast<char*> (&m_bSGMUpper), sizeof(m_bSGMUpper));
204
stream.read(reinterpret_cast<char*> (&m_bSGMLower), sizeof(m_bSGMLower));
205
m_pMapper->LoadState(stream);
206
}
207
208
std::vector<CVMemory::stDisassembleRecord*>* CVMemory::GetBreakpointsCPU()
209
{
210
return &m_BreakpointsCPU;
211
}
212
213
std::vector<CVMemory::stMemoryBreakpoint>* CVMemory::GetBreakpointsMem()
214
{
215
return &m_BreakpointsMem;
216
}
217
218
CVMemory::stDisassembleRecord* CVMemory::GetRunToBreakpoint()
219
{
220
return m_pRunToBreakpoint;
221
}
222
223
void CVMemory::SetRunToBreakpoint(CVMemory::stDisassembleRecord* pBreakpoint)
224
{
225
m_pRunToBreakpoint = pBreakpoint;
226
}
227
228
void CVMemory::LoadBios(const char* szFilePath)
229
{
230
using namespace std;
231
232
m_bBiosLoaded = false;
233
234
ifstream file;
235
open_ifstream_utf8(file, szFilePath, ios::in | ios::binary | ios::ate);
236
237
if (file.is_open())
238
{
239
int size = static_cast<int> (file.tellg());
240
241
if (size != 0x2000)
242
{
243
Log("Incorrect BIOS size %d: %s", size, szFilePath);
244
return;
245
}
246
247
file.seekg(0, ios::beg);
248
file.read(reinterpret_cast<char*>(m_pBios), size);
249
file.close();
250
251
m_bBiosLoaded = true;
252
253
Log("BIOS %s loaded (%d bytes)", szFilePath, size);
254
}
255
else
256
{
257
Log("There was a problem opening the file %s", szFilePath);
258
}
259
}
260
261
u8* CVMemory::GetRam()
262
{
263
return m_pRam;
264
}
265
266
u8* CVMemory::GetSGMRam()
267
{
268
return m_pSGMRam;
269
}
270
271
u8* CVMemory::GetBios()
272
{
273
return m_pBios;
274
}
275
276
u8 CVMemory::GetRomBank()
277
{
278
return IsValidPointer(m_pMapper) ? m_pMapper->GetRomBank() : 0;
279
}
280
281
u32 CVMemory::GetRomBankAddress()
282
{
283
return IsValidPointer(m_pMapper) ? m_pMapper->GetRomBankAddress() : 0;
284
}
285
286
bool CVMemory::IsBiosLoaded()
287
{
288
return m_bBiosLoaded;
289
}
290
291
void CVMemory::EnableSGMUpper(bool enable)
292
{
293
m_bSGMUpper = enable;
294
}
295
296
void CVMemory::EnableSGMLower(bool enable)
297
{
298
m_bSGMLower = enable;
299
}
300
301
void CVMemory::CheckBreakpoints(u16 address, bool write)
302
{
303
size_t size = m_BreakpointsMem.size();
304
305
for (size_t b = 0; b < size; b++)
306
{
307
if (write && !m_BreakpointsMem[b].write)
308
continue;
309
310
if (!write && !m_BreakpointsMem[b].read)
311
continue;
312
313
bool proceed = false;
314
315
if (m_BreakpointsMem[b].range)
316
{
317
if ((address >= m_BreakpointsMem[b].address1) && (address <= m_BreakpointsMem[b].address2))
318
{
319
proceed = true;
320
}
321
}
322
else
323
{
324
if (m_BreakpointsMem[b].address1 == address)
325
{
326
proceed = true;
327
}
328
}
329
330
if (proceed)
331
{
332
m_pProcessor->RequestMemoryBreakpoint();
333
break;
334
}
335
}
336
}
337
338
void CVMemory::ResetRomDisassembledMemory()
339
{
340
#ifndef GEARCOLECO_DISABLE_DISSSEMBLER
341
342
m_BreakpointsCPU.clear();
343
344
if (IsValidPointer(m_pDisassembledRomMap))
345
{
346
for (int i = 0; i < MAX_ROM_SIZE; i++)
347
{
348
SafeDelete(m_pDisassembledRomMap[i]);
349
}
350
}
351
352
if (IsValidPointer(m_pDisassembledRamMap))
353
{
354
for (int i = 0; i < 0x400; i++)
355
{
356
SafeDelete(m_pDisassembledRamMap[i]);
357
}
358
}
359
360
if (IsValidPointer(m_pDisassembledBiosMap))
361
{
362
for (int i = 0; i < 0x2000; i++)
363
{
364
SafeDelete(m_pDisassembledBiosMap[i]);
365
}
366
}
367
368
if (IsValidPointer(m_pDisassembledSGMRamMap))
369
{
370
for (int i = 0; i < 0x8000; i++)
371
{
372
SafeDelete(m_pDisassembledSGMRamMap[i]);
373
}
374
}
375
376
#endif
377
}
378
379
CVMemory::stDisassembleRecord* CVMemory::GetDisassembleRecord(u16 address, bool createIfNotFound)
380
{
381
#ifndef GEARCOLECO_DISABLE_DISSSEMBLER
382
383
stDisassembleRecord** map = NULL;
384
int offset = address;
385
int segment = 0;
386
int bank = 0;
387
388
switch (address & 0xE000)
389
{
390
case 0x0000:
391
{
392
offset = address;
393
map = m_bSGMLower ? m_pDisassembledSGMRamMap : m_pDisassembledBiosMap;
394
segment = m_bSGMLower ? 1 : 0;
395
break;
396
}
397
case 0x2000:
398
case 0x4000:
399
{
400
offset = address;
401
map = m_pDisassembledSGMRamMap;
402
segment = 1;
403
break;
404
}
405
case 0x6000:
406
{
407
offset = m_bSGMUpper ? address : address & 0x03FF;
408
map = m_bSGMUpper ? m_pDisassembledSGMRamMap : m_pDisassembledRamMap;
409
segment = m_bSGMUpper ? 1 : 2;
410
break;
411
}
412
default:
413
{
414
map = m_pDisassembledRomMap;
415
segment = 3;
416
417
switch (m_pCartridge->GetType())
418
{
419
case Cartridge::CartridgeMegaCart:
420
{
421
if (address < 0xC000)
422
{
423
offset = (address & 0x3FFF) + (m_pCartridge->GetROMSize() - 0x4000);
424
bank = m_pCartridge->GetROMBankCount() - 1;
425
}
426
else
427
{
428
offset = (address & 0x3FFF) + GetRomBankAddress();
429
bank = GetRomBank();
430
}
431
break;
432
}
433
case Cartridge::CartridgeActivisionCart:
434
{
435
if (address < 0xC000)
436
{
437
offset = address & 0x3FFF;
438
bank = 0;
439
}
440
else
441
{
442
offset = (address & 0x3FFF) + GetRomBankAddress();
443
bank = GetRomBank();
444
}
445
break;
446
}
447
case Cartridge::CartridgeOCM:
448
{
449
if (address < 0xA000)
450
{
451
// 8000-9FFF: Bank 3
452
offset = (address - 0x8000) + (m_pMapper->GetBankReg(3) * 0x2000);
453
bank = m_pMapper->GetBankReg(3);
454
}
455
else if (address < 0xC000)
456
{
457
// A000-BFFF: Bank 0
458
offset = (address - 0xA000) + (m_pMapper->GetBankReg(0) * 0x2000);
459
bank = m_pMapper->GetBankReg(0);
460
}
461
else if (address < 0xE000)
462
{
463
// C000-DFFF: Bank 1
464
offset = (address - 0xC000) + (m_pMapper->GetBankReg(1) * 0x2000);
465
bank = m_pMapper->GetBankReg(1);
466
}
467
else
468
{
469
// E000-FFFF: Bank 2
470
offset = (address - 0xE000) + (m_pMapper->GetBankReg(2) * 0x2000);
471
bank = m_pMapper->GetBankReg(2);
472
}
473
break;
474
}
475
default:
476
{
477
offset = address - 0x8000;
478
bank = 0;
479
break;
480
}
481
}
482
}
483
}
484
485
if (!IsValidPointer(map[offset]) && createIfNotFound)
486
{
487
map[offset] = new CVMemory::stDisassembleRecord;
488
489
map[offset]->address = address;
490
map[offset]->bank = bank;
491
map[offset]->name[0] = 0;
492
map[offset]->bytes[0] = 0;
493
map[offset]->size = 0;
494
for (int i = 0; i < 4; i++)
495
map[offset]->opcodes[i] = 0;
496
map[offset]->jump = false;
497
map[offset]->jump_address = 0;
498
499
switch (segment)
500
{
501
case 0:
502
{
503
strcpy(map[offset]->segment, "BIOS");
504
break;
505
}
506
case 1:
507
{
508
strcpy(map[offset]->segment, "SGM ");
509
break;
510
}
511
case 2:
512
{
513
strcpy(map[offset]->segment, "RAM ");
514
break;
515
}
516
case 3:
517
{
518
strcpy(map[offset]->segment, "ROM");
519
break;
520
}
521
}
522
}
523
524
return map[offset];
525
526
#else
527
528
return NULL;
529
530
#endif
531
}
532
533