Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
folium-app
GitHub Repository: folium-app/Folium
Path: blob/a-new-beginning/Cherry/Core/Cartridge.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 <string>
21
#include <algorithm>
22
#include <ctype.h>
23
#include "Cartridge.h"
24
#include "miniz/miniz.h"
25
#include "game_db.h"
26
#include "common.h"
27
28
Cartridge::Cartridge()
29
{
30
InitPointer(m_pROM);
31
InitPointer(m_pEEPROM);
32
m_iROMSize = 0;
33
m_Type = CartridgeNotSupported;
34
m_bValidROM = false;
35
m_bReady = false;
36
m_szFilePath[0] = 0;
37
m_szFileName[0] = 0;
38
m_iROMBankCount = 0;
39
m_bPAL = false;
40
m_bSRAM = false;
41
m_iCRC = 0;
42
}
43
44
Cartridge::~Cartridge()
45
{
46
SafeDeleteArray(m_pROM);
47
SafeDeleteArray(m_pEEPROM);
48
}
49
50
void Cartridge::Init()
51
{
52
m_pEEPROM = new u8[0x400];
53
Reset();
54
}
55
56
void Cartridge::Reset()
57
{
58
SafeDeleteArray(m_pROM);
59
m_iROMSize = 0;
60
m_Type = CartridgeNotSupported;
61
m_bValidROM = false;
62
m_bReady = false;
63
m_szFilePath[0] = 0;
64
m_szFileName[0] = 0;
65
m_iROMBankCount = 0;
66
m_bPAL = false;
67
m_bSRAM = false;
68
m_iCRC = 0;
69
for (int j = 0; j < 0x400; j++)
70
m_pEEPROM[j] = 0xFF;
71
}
72
73
u32 Cartridge::GetCRC() const
74
{
75
return m_iCRC;
76
}
77
78
bool Cartridge::IsPAL() const
79
{
80
return m_bPAL;
81
}
82
83
bool Cartridge::HasSRAM() const
84
{
85
return m_bSRAM;
86
}
87
88
bool Cartridge::IsValidROM() const
89
{
90
return m_bValidROM;
91
}
92
93
bool Cartridge::IsReady() const
94
{
95
return m_bReady;
96
}
97
98
Cartridge::CartridgeTypes Cartridge::GetType() const
99
{
100
return m_Type;
101
}
102
103
void Cartridge::ForceConfig(Cartridge::ForceConfiguration config)
104
{
105
m_iCRC = CalculateCRC32(0, m_pROM, m_iROMSize);
106
GatherMetadata(m_iCRC);
107
108
if (config.region == CartridgePAL)
109
{
110
Log("Forcing Region: PAL");
111
m_bPAL = true;
112
}
113
else if (config.region == CartridgeNTSC)
114
{
115
Log("Forcing Region: NTSC");
116
m_bPAL = false;
117
}
118
119
switch (config.type)
120
{
121
case Cartridge::CartridgeColecoVision:
122
m_Type = config.type;
123
Log("Forcing Mapper: Colecovision");
124
break;
125
case Cartridge::CartridgeMegaCart:
126
m_Type = config.type;
127
Log("Forcing Mapper: MegaCart");
128
break;
129
case Cartridge::CartridgeActivisionCart:
130
m_Type = config.type;
131
Log("Forcing Mapper: Activision");
132
break;
133
case Cartridge::CartridgeOCM:
134
m_Type = config.type;
135
Log("Forcing Mapper: OCM");
136
break;
137
default:
138
break;
139
}
140
}
141
142
int Cartridge::GetROMSize() const
143
{
144
return m_iROMSize;
145
}
146
147
int Cartridge::GetROMBankCount() const
148
{
149
return m_iROMBankCount;
150
}
151
152
const char* Cartridge::GetFilePath() const
153
{
154
return m_szFilePath;
155
}
156
157
const char* Cartridge::GetFileName() const
158
{
159
return m_szFileName;
160
}
161
162
u8* Cartridge::GetROM() const
163
{
164
return m_pROM;
165
}
166
167
u8* Cartridge::GetEEPROM() const
168
{
169
return m_pEEPROM;
170
}
171
172
bool Cartridge::LoadFromZipFile(const u8* buffer, int size)
173
{
174
using namespace std;
175
176
mz_zip_archive zip_archive;
177
mz_bool status;
178
memset(&zip_archive, 0, sizeof (zip_archive));
179
180
status = mz_zip_reader_init_mem(&zip_archive, (void*) buffer, size, 0);
181
if (!status)
182
{
183
Log("mz_zip_reader_init_mem() failed!");
184
return false;
185
}
186
187
for (unsigned int i = 0; i < mz_zip_reader_get_num_files(&zip_archive); i++)
188
{
189
mz_zip_archive_file_stat file_stat;
190
if (!mz_zip_reader_file_stat(&zip_archive, i, &file_stat))
191
{
192
Log("mz_zip_reader_file_stat() failed!");
193
mz_zip_reader_end(&zip_archive);
194
return false;
195
}
196
197
Debug("ZIP Content - Filename: \"%s\", Comment: \"%s\", Uncompressed size: %u, Compressed size: %u", file_stat.m_filename, file_stat.m_comment, (unsigned int) file_stat.m_uncomp_size, (unsigned int) file_stat.m_comp_size);
198
199
string fn((const char*) file_stat.m_filename);
200
transform(fn.begin(), fn.end(), fn.begin(), (int(*)(int)) tolower);
201
string extension = fn.substr(fn.find_last_of(".") + 1);
202
203
if ((extension == "col") || (extension == "cv") || (extension == "rom") || (extension == "bin"))
204
{
205
void *p;
206
size_t uncomp_size;
207
208
p = mz_zip_reader_extract_file_to_heap(&zip_archive, file_stat.m_filename, &uncomp_size, 0);
209
if (!p)
210
{
211
Log("mz_zip_reader_extract_file_to_heap() failed!");
212
mz_zip_reader_end(&zip_archive);
213
return false;
214
}
215
216
bool ok = LoadFromBuffer((const u8*) p, (int)uncomp_size);
217
218
free(p);
219
mz_zip_reader_end(&zip_archive);
220
221
return ok;
222
}
223
}
224
return false;
225
}
226
227
bool Cartridge::LoadFromFile(const char* path)
228
{
229
using namespace std;
230
231
Log("Loading %s...", path);
232
233
Reset();
234
235
strcpy(m_szFilePath, path);
236
237
std::string pathstr(path);
238
std::string filename;
239
240
size_t pos = pathstr.find_last_of("\\");
241
if (pos != std::string::npos)
242
{
243
filename.assign(pathstr.begin() + pos + 1, pathstr.end());
244
}
245
else
246
{
247
pos = pathstr.find_last_of("/");
248
if (pos != std::string::npos)
249
{
250
filename.assign(pathstr.begin() + pos + 1, pathstr.end());
251
}
252
else
253
{
254
filename = pathstr;
255
}
256
}
257
258
strcpy(m_szFileName, filename.c_str());
259
260
ifstream file;
261
open_ifstream_utf8(file, path, ios::in | ios::binary | ios::ate);
262
263
if (file.is_open())
264
{
265
int size = static_cast<int> (file.tellg());
266
char* memblock = new char[size];
267
file.seekg(0, ios::beg);
268
file.read(memblock, size);
269
file.close();
270
271
string fn(path);
272
transform(fn.begin(), fn.end(), fn.begin(), (int(*)(int)) tolower);
273
string extension = fn.substr(fn.find_last_of(".") + 1);
274
275
if (extension == "zip")
276
{
277
Debug("Loading from ZIP...");
278
m_bReady = LoadFromZipFile(reinterpret_cast<u8*> (memblock), size);
279
}
280
else
281
{
282
m_bReady = LoadFromBuffer(reinterpret_cast<u8*> (memblock), size);
283
}
284
285
if (m_bReady)
286
{
287
Debug("ROM loaded", path);
288
}
289
else
290
{
291
Log("There was a problem loading the memory for file %s...", path);
292
}
293
294
SafeDeleteArray(memblock);
295
}
296
else
297
{
298
Log("There was a problem loading the file %s...", path);
299
m_bReady = false;
300
}
301
302
if (!m_bReady)
303
{
304
Reset();
305
}
306
307
return m_bReady;
308
}
309
310
bool Cartridge::LoadFromBuffer(const u8* buffer, int size)
311
{
312
if (IsValidPointer(buffer))
313
{
314
Log("Loading from buffer... Size: %d", size);
315
316
// Unkown size
317
if ((size % 1024) != 0)
318
{
319
Log("Invalid size found. %d bytes", size);
320
//return false;
321
}
322
323
m_iROMSize = size;
324
m_pROM = new u8[m_iROMSize];
325
memcpy(m_pROM, buffer, m_iROMSize);
326
327
m_bReady = true;
328
329
m_iCRC = CalculateCRC32(0, m_pROM, m_iROMSize);
330
331
GatherMetadata(m_iCRC);
332
333
return true;
334
}
335
else
336
return false;
337
}
338
339
bool Cartridge::GatherMetadata(u32 crc)
340
{
341
m_bPAL = false;
342
m_bSRAM = false;
343
344
Log("ROM Size: %d KB", m_iROMSize / 1024);
345
346
m_iROMBankCount = (m_iROMSize / 0x4000) + (m_iROMSize % 0x4000 ? 1 : 0);
347
348
Log("ROM Bank Count: %d", m_iROMBankCount);
349
350
m_Type = Cartridge::CartridgeNotSupported;
351
352
int headerOffset = 0;
353
u16 header = m_pROM[headerOffset + 1] | (m_pROM[headerOffset + 0] << 8);
354
m_bValidROM = (header == 0xAA55) || (header == 0x55AA);
355
356
if (header == 0x6699)
357
{
358
Log("Cartridge is a Colec Adam expansion ROM. Header: %X", header);
359
}
360
361
if (m_bValidROM && (m_iROMSize <= 0x8000))
362
{
363
m_Type = Cartridge::CartridgeColecoVision;
364
Log("Cartridge is Colecovision. ROM size: %d bytes.", m_iROMSize);
365
}
366
else if (m_bValidROM && (m_iROMSize > 0x8000))
367
{
368
m_Type = Cartridge::CartridgeActivisionCart;
369
Log("Cartridge is Activision Cart. ROM size: %d bytes. Banks %d.", m_iROMSize, m_iROMBankCount);
370
}
371
else if (!m_bValidROM && (m_iROMSize > 0x8000))
372
{
373
headerOffset = m_iROMSize - 0x4000;
374
header = m_pROM[headerOffset + 1] | (m_pROM[headerOffset + 0] << 8);
375
m_bValidROM = (header == 0xAA55) || (header == 0x55AA);
376
377
if (m_bValidROM)
378
{
379
m_Type = Cartridge::CartridgeMegaCart;
380
Log("Cartridge is Mega Cart. ROM size: %d bytes. Banks %d.", m_iROMSize, m_iROMBankCount);
381
}
382
}
383
else
384
{
385
m_Type = Cartridge::CartridgeNotSupported;
386
Log("ROM is NOT Valid. No header found.");
387
}
388
389
GetInfoFromDB(crc);
390
391
switch (m_Type)
392
{
393
case Cartridge::CartridgeColecoVision:
394
Log("ColecoVision mapper found");
395
break;
396
case Cartridge::CartridgeMegaCart:
397
Log("MegaCart mapper found");
398
break;
399
case Cartridge::CartridgeActivisionCart:
400
Log("Activision mapper found");
401
break;
402
case Cartridge::CartridgeOCM:
403
Log("OCM mapper found");
404
break;
405
case Cartridge::CartridgeNotSupported:
406
Log("Cartridge not supported!!");
407
break;
408
default:
409
Log("ERROR with cartridge type!!");
410
break;
411
}
412
413
return (m_Type != CartridgeNotSupported);
414
}
415
416
void Cartridge::GetInfoFromDB(u32 crc)
417
{
418
int i = 0;
419
bool found = false;
420
421
while(!found && (kGameDatabase[i].title != 0))
422
{
423
u32 db_crc = kGameDatabase[i].crc;
424
425
if (db_crc == crc)
426
{
427
found = true;
428
429
Log("ROM found in database: %s. CRC: %X", kGameDatabase[i].title, crc);
430
431
if (kGameDatabase[i].mode & GC_GameDBMode_SRAM)
432
{
433
Log("Cartridge with SRAM");
434
m_bSRAM = true;
435
}
436
437
if (kGameDatabase[i].mode & GC_GameDBMode_OCM)
438
{
439
Log("Cartridge with OCM mapper");
440
m_Type = CartridgeOCM;
441
for (int j = 0; j < 0x400; j++)
442
m_pEEPROM[j] = 0xFF;
443
}
444
}
445
else
446
i++;
447
}
448
449
if (!found)
450
{
451
Debug("ROM not found in database. CRC: %X", crc);
452
}
453
}
454
455