Cartridge.cpp (15483B)
1/* 2 * Gearboy - Nintendo Game Boy Emulator 3 * Copyright (C) 2012 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 <time.h> 24#include "Cartridge.h" 25#include "miniz/miniz.c" 26 27Cartridge::Cartridge() 28{ 29 InitPointer(m_pTheROM); 30 m_iTotalSize = 0; 31 m_szName[0] = 0; 32 m_iROMSize = 0; 33 m_iRAMSize = 0; 34 m_Type = CartridgeNotSupported; 35 m_bValidROM = false; 36 m_bCGB = false; 37 m_bSGB = false; 38 m_iVersion = 0; 39 m_bLoaded = false; 40 m_RTCCurrentTime = 0; 41 m_bBattery = false; 42 m_szFilePath[0] = 0; 43 m_szFileName[0] = 0; 44 m_bRTCPresent = false; 45 m_bRumblePresent = false; 46 m_iRAMBankCount = 0; 47 m_iROMBankCount = 0; 48} 49 50Cartridge::~Cartridge() 51{ 52 SafeDeleteArray(m_pTheROM); 53} 54 55void Cartridge::Init() 56{ 57 Reset(); 58} 59 60void Cartridge::Reset() 61{ 62 SafeDeleteArray(m_pTheROM); 63 m_iTotalSize = 0; 64 m_szName[0] = 0; 65 m_iROMSize = 0; 66 m_iRAMSize = 0; 67 m_Type = CartridgeNotSupported; 68 m_bValidROM = false; 69 m_bCGB = false; 70 m_bSGB = false; 71 m_iVersion = 0; 72 m_bLoaded = false; 73 m_RTCCurrentTime = 0; 74 m_bBattery = false; 75 m_szFilePath[0] = 0; 76 m_szFileName[0] = 0; 77 m_bRTCPresent = false; 78 m_bRumblePresent = false; 79 m_iRAMBankCount = 0; 80 m_iROMBankCount = 0; 81 m_GameGenieList.clear(); 82} 83 84bool Cartridge::IsValidROM() const 85{ 86 return m_bValidROM; 87} 88 89bool Cartridge::IsLoadedROM() const 90{ 91 return m_bLoaded; 92} 93 94Cartridge::CartridgeTypes Cartridge::GetType() const 95{ 96 return m_Type; 97} 98 99int Cartridge::GetRAMSize() const 100{ 101 return m_iRAMSize; 102} 103 104int Cartridge::GetROMSize() const 105{ 106 return m_iROMSize; 107} 108 109int Cartridge::GetRAMBankCount() const 110{ 111 return m_iRAMBankCount; 112} 113 114int Cartridge::GetROMBankCount() const 115{ 116 return m_iROMBankCount; 117} 118 119const char* Cartridge::GetName() const 120{ 121 return m_szName; 122} 123 124const char* Cartridge::GetFilePath() const 125{ 126 return m_szFilePath; 127} 128 129const char* Cartridge::GetFileName() const 130{ 131 return m_szFileName; 132} 133 134int Cartridge::GetTotalSize() const 135{ 136 return m_iTotalSize; 137} 138 139bool Cartridge::HasBattery() const 140{ 141 return m_bBattery; 142} 143 144u8* Cartridge::GetTheROM() const 145{ 146 return m_pTheROM; 147} 148 149bool Cartridge::LoadFromZipFile(const u8* buffer, int size) 150{ 151 using namespace std; 152 153 mz_zip_archive zip_archive; 154 mz_bool status; 155 memset(&zip_archive, 0, sizeof (zip_archive)); 156 157 status = mz_zip_reader_init_mem(&zip_archive, (void*) buffer, size, 0); 158 if (!status) 159 { 160 Log("mz_zip_reader_init_mem() failed!"); 161 return false; 162 } 163 164 for (unsigned int i = 0; i < mz_zip_reader_get_num_files(&zip_archive); i++) 165 { 166 mz_zip_archive_file_stat file_stat; 167 if (!mz_zip_reader_file_stat(&zip_archive, i, &file_stat)) 168 { 169 Log("mz_zip_reader_file_stat() failed!"); 170 mz_zip_reader_end(&zip_archive); 171 return false; 172 } 173 174 Log("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); 175 176 string fn((const char*) file_stat.m_filename); 177 transform(fn.begin(), fn.end(), fn.begin(), (int(*)(int)) tolower); 178 string extension = fn.substr(fn.find_last_of(".") + 1); 179 180 if ((extension == "gb") || (extension == "dmg") || (extension == "gbc") || (extension == "cgb") || (extension == "sgb")) 181 { 182 void *p; 183 size_t uncomp_size; 184 185 p = mz_zip_reader_extract_file_to_heap(&zip_archive, file_stat.m_filename, &uncomp_size, 0); 186 if (!p) 187 { 188 Log("mz_zip_reader_extract_file_to_heap() failed!"); 189 mz_zip_reader_end(&zip_archive); 190 return false; 191 } 192 193 bool ok = LoadFromBuffer((const u8*) p, static_cast<int>(uncomp_size)); 194 195 free(p); 196 mz_zip_reader_end(&zip_archive); 197 198 return ok; 199 } 200 } 201 return false; 202} 203 204bool Cartridge::LoadFromFile(const char* path) 205{ 206 using namespace std; 207 208 Log("Loading %s...", path); 209 210 Reset(); 211 212 strcpy(m_szFilePath, path); 213 214 std::string pathstr(path); 215 std::string filename; 216 217 size_t pos = pathstr.find_last_of("\\"); 218 if (pos != std::string::npos) 219 { 220 filename.assign(pathstr.begin() + pos + 1, pathstr.end()); 221 } 222 else 223 { 224 pos = pathstr.find_last_of("/"); 225 if (pos != std::string::npos) 226 { 227 filename.assign(pathstr.begin() + pos + 1, pathstr.end()); 228 } 229 else 230 { 231 filename = pathstr; 232 } 233 } 234 235 strcpy(m_szFileName, filename.c_str()); 236 237 ifstream file(path, ios::in | ios::binary | ios::ate); 238 239 if (file.is_open()) 240 { 241 int size = static_cast<int> (file.tellg()); 242 char* memblock = new char[size]; 243 file.seekg(0, ios::beg); 244 file.read(memblock, size); 245 file.close(); 246 247 string fn(path); 248 transform(fn.begin(), fn.end(), fn.begin(), (int(*)(int)) tolower); 249 string extension = fn.substr(fn.find_last_of(".") + 1); 250 251 if (extension == "zip") 252 { 253 Log("Loading from ZIP..."); 254 m_bLoaded = LoadFromZipFile(reinterpret_cast<u8*> (memblock), size); 255 } 256 else 257 { 258 m_bLoaded = LoadFromBuffer(reinterpret_cast<u8*> (memblock), size); 259 } 260 261 if (m_bLoaded) 262 { 263 Log("ROM loaded", path); 264 } 265 else 266 { 267 Log("There was a problem loading the memory for file %s...", path); 268 } 269 270 SafeDeleteArray(memblock); 271 } 272 else 273 { 274 Log("There was a problem loading the file %s...", path); 275 m_bLoaded = false; 276 } 277 278 if (!m_bLoaded) 279 { 280 Reset(); 281 } 282 283 return m_bLoaded; 284} 285 286bool Cartridge::LoadFromBuffer(const u8* buffer, int size) 287{ 288 if (IsValidPointer(buffer)) 289 { 290 Log("Loading from buffer... Size: %d", size); 291 m_iTotalSize = size; 292 m_pTheROM = new u8[m_iTotalSize]; 293 memcpy(m_pTheROM, buffer, m_iTotalSize); 294 m_bLoaded = true; 295 return GatherMetadata(); 296 } 297 else 298 return false; 299} 300 301void Cartridge::CheckCartridgeType(int type) 302{ 303 if ((type != 0xEA) && (GetROMSize() == 0)) 304 type = 0; 305 306 switch (type) 307 { 308 case 0x00: 309 // NO MBC 310 case 0x08: 311 // ROM 312 // SRAM 313 case 0x09: 314 // ROM 315 // SRAM 316 // BATT 317 m_Type = CartridgeNoMBC; 318 break; 319 case 0x01: 320 // MBC1 321 case 0x02: 322 // MBC1 323 // SRAM 324 case 0x03: 325 // MBC1 326 // SRAM 327 // BATT 328 case 0xEA: 329 // Hack to accept 0xEA as a MBC1 (Sonic 3D Blast 5) 330 case 0xFF: 331 // Hack to accept HuC1 as a MBC1 332 m_Type = CartridgeMBC1; 333 break; 334 case 0x05: 335 // MBC2 336 // SRAM 337 case 0x06: 338 // MBC2 339 // SRAM 340 // BATT 341 m_Type = CartridgeMBC2; 342 break; 343 case 0x0F: 344 // MBC3 345 // TIMER 346 // BATT 347 case 0x10: 348 // MBC3 349 // TIMER 350 // BATT 351 // SRAM 352 case 0x11: 353 // MBC3 354 case 0x12: 355 // MBC3 356 // SRAM 357 case 0x13: 358 // MBC3 359 // BATT 360 // SRAM 361 case 0xFC: 362 // Game Boy Camera 363 m_Type = CartridgeMBC3; 364 break; 365 case 0x19: 366 // MBC5 367 case 0x1A: 368 // MBC5 369 // SRAM 370 case 0x1B: 371 // MBC5 372 // BATT 373 // SRAM 374 case 0x1C: 375 // RUMBLE 376 case 0x1D: 377 // RUMBLE 378 // SRAM 379 case 0x1E: 380 // RUMBLE 381 // BATT 382 // SRAM 383 m_Type = CartridgeMBC5; 384 break; 385 case 0x0B: 386 // MMMO1 387 case 0x0C: 388 // MMM01 389 // SRAM 390 case 0x0D: 391 // MMM01 392 // SRAM 393 // BATT 394 case 0x15: 395 // MBC4 396 case 0x16: 397 // MBC4 398 // SRAM 399 case 0x17: 400 // MBC4 401 // SRAM 402 // BATT 403 case 0x22: 404 // MBC7 405 // BATT 406 // SRAM 407 case 0x55: 408 // GG 409 case 0x56: 410 // GS3 411 case 0xFD: 412 // TAMA 5 413 case 0xFE: 414 // HuC3 415 m_Type = CartridgeNotSupported; 416 Log("--> ** This cartridge is not supported. Type: %d", type); 417 break; 418 default: 419 m_Type = CartridgeNotSupported; 420 Log("--> ** Unknown cartridge type: %d", type); 421 } 422 423 switch (type) 424 { 425 case 0x03: 426 case 0x06: 427 case 0x09: 428 case 0x0D: 429 case 0x0F: 430 case 0x10: 431 case 0x13: 432 case 0x17: 433 case 0x1B: 434 case 0x1E: 435 case 0x22: 436 case 0xFD: 437 case 0xFF: 438 m_bBattery = true; 439 break; 440 default: 441 m_bBattery = false; 442 } 443 444 switch (type) 445 { 446 case 0x0F: 447 case 0x10: 448 m_bRTCPresent = true; 449 break; 450 default: 451 m_bRTCPresent = false; 452 } 453 454 switch (type) 455 { 456 case 0x1C: 457 case 0x1D: 458 case 0x1E: 459 m_bRumblePresent = true; 460 break; 461 default: 462 m_bRumblePresent = false; 463 } 464} 465 466int Cartridge::GetVersion() const 467{ 468 return m_iVersion; 469} 470 471bool Cartridge::IsSGB() const 472{ 473 return m_bSGB; 474} 475 476bool Cartridge::IsCGB() const 477{ 478 return m_bCGB; 479} 480 481void Cartridge::UpdateCurrentRTC() 482{ 483 time(&m_RTCCurrentTime); 484} 485 486time_t Cartridge::GetCurrentRTC() 487{ 488 return m_RTCCurrentTime; 489} 490 491bool Cartridge::IsRTCPresent() const 492{ 493 return m_bRTCPresent; 494} 495 496bool Cartridge::IsRumblePresent() const 497{ 498 return m_bRumblePresent; 499} 500 501void Cartridge::SetGameGenieCheat(const char* szCheat) 502{ 503 std::string code(szCheat); 504 for (std::string::iterator p = code.begin(); code.end() != p; ++p) 505 *p = toupper(*p); 506 507 if (m_bLoaded && (code.length() > 6) && ((code[3] < '0') || ((code[3] > '9') && (code[3] < 'A')))) 508 { 509 u8 new_value = (AsHex(code[0]) << 4 | AsHex(code[1])) & 0xFF; 510 u16 cheat_address = (AsHex(code[2]) << 8 | AsHex(code[4]) << 4 | AsHex(code[5]) | (AsHex(code[6]) ^ 0xF) << 12) & 0x7FFF; 511 bool avoid_compare = true; 512 u8 compare_value = 0; 513 514 if ((code.length() == 11) && ((code[7] < '0') || ((code[7] > '9') && (code[7] < 'A')))) 515 { 516 compare_value = (AsHex(code[8]) << 4 | AsHex(code[10])) ^ 0xFF; 517 compare_value = ((compare_value >> 2 | compare_value << 6) ^ 0x45) & 0xFF; 518 avoid_compare = false; 519 } 520 521 for (int bank = 0; bank < GetROMBankCount(); bank++) 522 { 523 int bank_address = (bank * 0x4000) + (cheat_address & 0x3FFF); 524 525 if (avoid_compare || (m_pTheROM[bank_address] == compare_value)) 526 { 527 GameGenieCode undo_data; 528 undo_data.address = bank_address; 529 undo_data.old_value = m_pTheROM[bank_address]; 530 531 m_pTheROM[bank_address] = new_value; 532 533 m_GameGenieList.push_back(undo_data); 534 } 535 } 536 } 537} 538 539void Cartridge::ClearGameGenieCheats() 540{ 541 std::list<GameGenieCode>::iterator it; 542 543 for (it = m_GameGenieList.begin(); it != m_GameGenieList.end(); it++) 544 { 545 m_pTheROM[it->address] = it->old_value; 546 } 547 548 m_GameGenieList.clear(); 549} 550 551unsigned int Cartridge::Pow2Ceil(unsigned int n) 552{ 553 --n; 554 n |= n >> 1; 555 n |= n >> 2; 556 n |= n >> 4; 557 n |= n >> 8; 558 ++n; 559 return n; 560} 561 562bool Cartridge::GatherMetadata() 563{ 564 char name[12] = {0}; 565 name[11] = 0; 566 567 for (int i = 0; i < 11; i++) 568 { 569 name[i] = m_pTheROM[0x0134 + i]; 570 571 if (name[i] == 0) 572 { 573 break; 574 } 575 } 576 577 strcpy(m_szName, name); 578 579 m_bCGB = (m_pTheROM[0x143] == 0x80) || (m_pTheROM[0x143] == 0xC0); 580 m_bSGB = (m_pTheROM[0x146] == 0x03); 581 int type = m_pTheROM[0x147]; 582 m_iROMSize = m_pTheROM[0x148]; 583 m_iRAMSize = m_pTheROM[0x149]; 584 m_iVersion = m_pTheROM[0x14C]; 585 586 CheckCartridgeType(type); 587 588 switch (m_iRAMSize) 589 { 590 case 0x00: 591 m_iRAMBankCount = (m_Type == Cartridge::CartridgeMBC2) ? 1 : 0; 592 break; 593 case 0x01: 594 case 0x02: 595 m_iRAMBankCount = 1; 596 break; 597 case 0x04: 598 m_iRAMBankCount = 16; 599 break; 600 default: 601 m_iRAMBankCount = 4; 602 break; 603 } 604 605 m_iROMBankCount = std::max(Pow2Ceil(m_iTotalSize / 0x4000), 2u); 606 607 bool presumeMultiMBC1 = ((type == 1) && (m_iRAMSize == 0) && (m_iROMBankCount == 64)); 608 609 if ((m_Type == Cartridge::CartridgeMBC1) && presumeMultiMBC1) 610 { 611 m_Type = Cartridge::CartridgeMBC1Multi; 612 Log("Presumed Multi 64"); 613 } 614 615 Log("Cartridge Size %d", m_iTotalSize); 616 Log("ROM Name %s", m_szName); 617 Log("ROM Version %d", m_iVersion); 618 Log("ROM Type %X", type); 619 Log("ROM Size %X", m_iROMSize); 620 Log("ROM Bank Count %d", m_iROMBankCount); 621 Log("RAM Size %X", m_iRAMSize); 622 Log("RAM Bank Count %d", m_iRAMBankCount); 623 624 switch (m_Type) 625 { 626 case Cartridge::CartridgeNoMBC: 627 Log("No MBC found"); 628 break; 629 case Cartridge::CartridgeMBC1: 630 Log("MBC1 found"); 631 break; 632 case Cartridge::CartridgeMBC1Multi: 633 Log("MBC1 Multi 64 found"); 634 break; 635 case Cartridge::CartridgeMBC2: 636 Log("MBC2 found"); 637 break; 638 case Cartridge::CartridgeMBC3: 639 Log("MBC3 found"); 640 break; 641 case Cartridge::CartridgeMBC5: 642 Log("MBC5 found"); 643 break; 644 case Cartridge::CartridgeNotSupported: 645 Log("Cartridge not supported!!"); 646 break; 647 default: 648 break; 649 } 650 651 if (m_bBattery) 652 { 653 Log("Battery powered RAM found"); 654 } 655 656 if (m_pTheROM[0x143] == 0xC0) 657 { 658 Log("Game Boy Color only"); 659 } 660 else if (m_bCGB) 661 { 662 Log("Game Boy Color supported"); 663 } 664 665 if (m_bSGB) 666 { 667 Log("Super Game Boy supported"); 668 } 669 670 int checksum = 0; 671 672 for (int j = 0x134; j < 0x14E; j++) 673 { 674 checksum += m_pTheROM[j]; 675 } 676 677 m_bValidROM = ((checksum + 25) & 0xFF) == 0; 678 679 if (m_bValidROM) 680 { 681 Log("Checksum OK!"); 682 } 683 else 684 { 685 Log("Checksum FAILED!!!"); 686 } 687 688 return (m_Type != CartridgeNotSupported); 689}