GearboyCore.cpp (25505B)
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 "GearboyCore.h" 21#include "Memory.h" 22#include "Processor.h" 23#include "Video.h" 24#include "Audio.h" 25#include "Input.h" 26#include "Cartridge.h" 27#include "MemoryRule.h" 28#include "CommonMemoryRule.h" 29#include "IORegistersMemoryRule.h" 30#include "RomOnlyMemoryRule.h" 31#include "MBC1MemoryRule.h" 32#include "MBC2MemoryRule.h" 33#include "MBC3MemoryRule.h" 34#include "MBC5MemoryRule.h" 35#include "MultiMBC1MemoryRule.h" 36 37GearboyCore::GearboyCore() 38{ 39 InitPointer(m_pMemory); 40 InitPointer(m_pProcessor); 41 InitPointer(m_pVideo); 42 InitPointer(m_pAudio); 43 InitPointer(m_pInput); 44 InitPointer(m_pCartridge); 45 InitPointer(m_pCommonMemoryRule); 46 InitPointer(m_pIORegistersMemoryRule); 47 InitPointer(m_pRomOnlyMemoryRule); 48 InitPointer(m_pMBC1MemoryRule); 49 InitPointer(m_pMultiMBC1MemoryRule); 50 InitPointer(m_pMBC2MemoryRule); 51 InitPointer(m_pMBC3MemoryRule); 52 InitPointer(m_pMBC5MemoryRule); 53 InitPointer(m_pRamChangedCallback); 54 m_bCGB = false; 55 m_bGBA = false; 56 m_bPaused = false; 57 m_bForceDMG = false; 58 m_iRTCUpdateCount = 0; 59 m_pixelFormat = GB_PIXEL_RGB565; 60} 61 62GearboyCore::~GearboyCore() 63{ 64 SafeDelete(m_pMBC5MemoryRule); 65 SafeDelete(m_pMBC3MemoryRule); 66 SafeDelete(m_pMBC2MemoryRule); 67 SafeDelete(m_pMultiMBC1MemoryRule); 68 SafeDelete(m_pMBC1MemoryRule); 69 SafeDelete(m_pRomOnlyMemoryRule); 70 SafeDelete(m_pIORegistersMemoryRule); 71 SafeDelete(m_pCommonMemoryRule); 72 SafeDelete(m_pCartridge); 73 SafeDelete(m_pInput); 74 SafeDelete(m_pAudio); 75 SafeDelete(m_pVideo); 76 SafeDelete(m_pProcessor); 77 SafeDelete(m_pMemory); 78} 79 80void GearboyCore::Init(GB_Color_Format pixelFormat) 81{ 82 Log("--== %s %s by Ignacio Sanchez ==--", GEARBOY_TITLE, GEARBOY_VERSION); 83 84 m_pixelFormat = pixelFormat; 85 86 m_pMemory = new Memory(); 87 m_pProcessor = new Processor(m_pMemory); 88 m_pVideo = new Video(m_pMemory, m_pProcessor); 89 m_pAudio = new Audio(); 90 m_pInput = new Input(m_pMemory, m_pProcessor); 91 m_pCartridge = new Cartridge(); 92 93 m_pMemory->Init(); 94 m_pProcessor->Init(); 95 m_pVideo->Init(); 96 m_pAudio->Init(); 97 m_pInput->Init(); 98 m_pCartridge->Init(); 99 100 InitMemoryRules(); 101 InitDMGPalette(); 102} 103 104bool GearboyCore::RunToVBlank(u16* pFrameBuffer, s16* pSampleBuffer, int* pSampleCount, bool bDMGbuffer, bool step, bool stopOnBreakpoints) 105{ 106 bool breakpoint = false; 107 108 if (!m_bPaused && m_pCartridge->IsLoadedROM()) 109 { 110 bool vblank = false; 111 int totalClocks = 0; 112 while (!vblank) 113 { 114 #ifdef PERFORMANCE 115 unsigned int clockCycles = m_pProcessor->RunFor(75); 116 #else 117 unsigned int clockCycles = m_pProcessor->RunFor(1); 118 #endif 119 120 m_pProcessor->UpdateTimers(clockCycles); 121 m_pProcessor->UpdateSerial(clockCycles); 122 123 vblank = m_pVideo->Tick(clockCycles, pFrameBuffer, m_pixelFormat); 124 m_pAudio->Tick(clockCycles); 125 m_pInput->Tick(clockCycles); 126 127 totalClocks += clockCycles; 128 129#ifndef GEARBOY_DISABLE_DISASSEMBLER 130 if ((step || (stopOnBreakpoints && m_pProcessor->BreakpointHit())) && !m_pProcessor->Halted() && !m_pProcessor->DuringOpCode()) 131 { 132 vblank = true; 133 if (m_pProcessor->BreakpointHit()) 134 breakpoint = true; 135 } 136#endif 137 138 if (totalClocks > 702240) 139 vblank = true; 140 } 141 142 m_pAudio->EndFrame(pSampleBuffer, pSampleCount); 143 144 m_iRTCUpdateCount++; 145 if (m_iRTCUpdateCount == 20) 146 { 147 m_iRTCUpdateCount = 0; 148 m_pCartridge->UpdateCurrentRTC(); 149 } 150 151 if (!m_bCGB && !bDMGbuffer) 152 { 153 RenderDMGFrame(pFrameBuffer); 154 } 155 } 156 157 return breakpoint; 158} 159 160bool GearboyCore::LoadROM(const char* szFilePath, bool forceDMG, Cartridge::CartridgeTypes forceType, bool forceGBA) 161{ 162 if (m_pCartridge->LoadFromFile(szFilePath)) 163 { 164 m_bForceDMG = forceDMG; 165 Reset(m_bForceDMG ? false : m_pCartridge->IsCGB(), forceGBA); 166 m_pMemory->ResetDisassembledMemory(); 167 m_pMemory->LoadBank0and1FromROM(m_pCartridge->GetTheROM()); 168 bool romTypeOK = AddMemoryRules(forceType); 169#ifndef GEARBOY_DISABLE_DISASSEMBLER 170 m_pProcessor->Disassemble(m_pProcessor->GetState()->PC->GetValue()); 171#endif 172 173 if (!romTypeOK) 174 { 175 Log("There was a problem with the cartridge header. File: %s...", szFilePath); 176 } 177 178 return romTypeOK; 179 } 180 else 181 return false; 182} 183 184bool GearboyCore::LoadROMFromBuffer(const u8* buffer, int size, bool forceDMG, Cartridge::CartridgeTypes forceType, bool forceGBA) 185{ 186 if (m_pCartridge->LoadFromBuffer(buffer, size)) 187 { 188 m_bForceDMG = forceDMG; 189 Reset(m_bForceDMG ? false : m_pCartridge->IsCGB(), forceGBA); 190 m_pMemory->ResetDisassembledMemory(); 191 m_pMemory->LoadBank0and1FromROM(m_pCartridge->GetTheROM()); 192 bool romTypeOK = AddMemoryRules(forceType); 193 194 if (!romTypeOK) 195 { 196 Log("There was a problem with the cartridge header."); 197 } 198 199 return romTypeOK; 200 } 201 else 202 return false; 203} 204 205void GearboyCore::SaveMemoryDump() 206{ 207 if (m_pCartridge->IsLoadedROM() && (strlen(m_pCartridge->GetFilePath()) > 0)) 208 { 209 using namespace std; 210 211 char path[512]; 212 213 strcpy(path, m_pCartridge->GetFilePath()); 214 strcat(path, ".dump"); 215 216 Log("Saving Memory Dump %s...", path); 217 218 m_pMemory->MemoryDump(path); 219 220 Log("Memory Dump Saved"); 221 } 222} 223 224void GearboyCore::SaveDisassembledROM() 225{ 226 Memory::stDisassembleRecord** romMap = m_pMemory->GetDisassembledROMMemoryMap(); 227 228 if (m_pCartridge->IsLoadedROM() && (strlen(m_pCartridge->GetFilePath()) > 0) && IsValidPointer(romMap)) 229 { 230 using namespace std; 231 232 char path[512]; 233 234 strcpy(path, m_pCartridge->GetFilePath()); 235 strcat(path, ".dis"); 236 237 Log("Saving Disassembled ROM %s...", path); 238 239 ofstream myfile(path, ios::out | ios::trunc); 240 241 if (myfile.is_open()) 242 { 243 for (int i = 0; i < 65536; i++) 244 { 245 if (IsValidPointer(romMap[i]) && (romMap[i]->name[0] != 0)) 246 { 247 myfile << "0x" << hex << i << "\t " << romMap[i]->name << "\n"; 248 i += (romMap[i]->size - 1); 249 } 250 } 251 252 myfile.close(); 253 } 254 255 Log("Disassembled ROM Saved"); 256 } 257} 258 259Memory* GearboyCore::GetMemory() 260{ 261 return m_pMemory; 262} 263 264Cartridge* GearboyCore::GetCartridge() 265{ 266 return m_pCartridge; 267} 268 269Processor* GearboyCore::GetProcessor() 270{ 271 return m_pProcessor; 272} 273 274Audio* GearboyCore::GetAudio() 275{ 276 return m_pAudio; 277} 278 279Video* GearboyCore::GetVideo() 280{ 281 return m_pVideo; 282} 283 284void GearboyCore::KeyPressed(Gameboy_Keys key) 285{ 286 m_pInput->KeyPressed(key); 287} 288 289void GearboyCore::KeyReleased(Gameboy_Keys key) 290{ 291 m_pInput->KeyReleased(key); 292} 293 294void GearboyCore::Pause(bool paused) 295{ 296 m_bPaused = paused; 297} 298 299bool GearboyCore::IsPaused() 300{ 301 return m_bPaused; 302} 303 304void GearboyCore::ResetROM(bool forceDMG, Cartridge::CartridgeTypes forceType, bool forceGBA) 305{ 306 if (m_pCartridge->IsLoadedROM()) 307 { 308 m_bForceDMG = forceDMG; 309 Reset(m_bForceDMG ? false : m_pCartridge->IsCGB(), forceGBA); 310 m_pMemory->LoadBank0and1FromROM(m_pCartridge->GetTheROM()); 311 AddMemoryRules(forceType); 312#ifndef GEARBOY_DISABLE_DISASSEMBLER 313 m_pProcessor->Disassemble(m_pProcessor->GetState()->PC->GetValue()); 314#endif 315 } 316} 317 318void GearboyCore::ResetROMPreservingRAM(bool forceDMG, Cartridge::CartridgeTypes forceType, bool forceGBA) 319{ 320 if (m_pCartridge->IsLoadedROM()) 321 { 322 Log("Resetting preserving RAM..."); 323 324 using namespace std; 325 stringstream stream; 326 327 m_pMemory->GetCurrentRule()->SaveRam(stream); 328 329 ResetROM(forceDMG, forceType, forceGBA); 330 331 stream.seekg(0, stream.end); 332 s32 size = (s32)stream.tellg(); 333 stream.seekg(0, stream.beg); 334 335 m_pMemory->GetCurrentRule()->LoadRam(stream, size); 336 } 337} 338 339void GearboyCore::ResetSound() 340{ 341 m_pAudio->Reset(m_bCGB); 342} 343 344void GearboyCore::SetSoundSampleRate(int rate) 345{ 346 m_pAudio->SetSampleRate(rate); 347} 348 349void GearboyCore::SetSoundVolume(float volume) 350{ 351 m_pAudio->SetVolume(volume); 352} 353 354u16* GearboyCore::GetDMGInternalPalette() 355{ 356 return m_DMGPalette; 357} 358 359void GearboyCore::SetDMGPalette(GB_Color& color1, GB_Color& color2, GB_Color& color3, 360 GB_Color& color4) 361{ 362 bool format_565 = (m_pixelFormat == GB_PIXEL_RGB565) || (m_pixelFormat == GB_PIXEL_BGR565); 363 bool order_RGB = (m_pixelFormat == GB_PIXEL_RGB565) || (m_pixelFormat == GB_PIXEL_RGB555); 364 365 int multiplier = format_565 ? 63 : 31; 366 int shift = format_565 ? 11 : 10; 367 368 if (order_RGB) 369 { 370 m_DMGPalette[0] = (((color1.red * 31) / 255) << shift ) | (((color1.green * multiplier) / 255) << 5 ) | ((color1.blue * 31) / 255); 371 m_DMGPalette[1] = (((color2.red * 31) / 255) << shift ) | (((color2.green * multiplier) / 255) << 5 ) | ((color2.blue * 31) / 255); 372 m_DMGPalette[2] = (((color3.red * 31) / 255) << shift ) | (((color3.green * multiplier) / 255) << 5 ) | ((color3.blue * 31) / 255); 373 m_DMGPalette[3] = (((color4.red * 31) / 255) << shift ) | (((color4.green * multiplier) / 255) << 5 ) | ((color4.blue * 31) / 255); 374 } 375 else 376 { 377 m_DMGPalette[0] = (((color1.blue * 31) / 255) << shift ) | (((color1.green * multiplier) / 255) << 5 ) | ((color1.red * 31) / 255); 378 m_DMGPalette[1] = (((color2.blue * 31) / 255) << shift ) | (((color2.green * multiplier) / 255) << 5 ) | ((color2.red * 31) / 255); 379 m_DMGPalette[2] = (((color3.blue * 31) / 255) << shift ) | (((color3.green * multiplier) / 255) << 5 ) | ((color3.red * 31) / 255); 380 m_DMGPalette[3] = (((color4.blue * 31) / 255) << shift ) | (((color4.green * multiplier) / 255) << 5 ) | ((color4.red * 31) / 255); 381 } 382 383 if (!format_565) 384 { 385 m_DMGPalette[0] |= 0x8000; 386 m_DMGPalette[1] |= 0x8000; 387 m_DMGPalette[2] |= 0x8000; 388 m_DMGPalette[3] |= 0x8000; 389 } 390} 391 392void GearboyCore::SaveRam() 393{ 394 SaveRam(NULL); 395} 396 397void GearboyCore::SaveRam(const char* szPath, bool fullPath) 398{ 399 if (m_pCartridge->IsLoadedROM() && m_pCartridge->HasBattery() && IsValidPointer(m_pMemory->GetCurrentRule())) 400 { 401 Log("Saving RAM..."); 402 403 using namespace std; 404 405 string path = ""; 406 407 if (IsValidPointer(szPath)) 408 { 409 path += szPath; 410 411 if (!fullPath) 412 { 413 path += "/"; 414 path += m_pCartridge->GetFileName(); 415 } 416 } 417 else 418 { 419 path = m_pCartridge->GetFilePath(); 420 } 421 422 string::size_type i = path.rfind('.', path.length()); 423 424 if (i != string::npos) { 425 path.replace(i + 1, 3, "sav"); 426 } 427 428 Log("Save file: %s", path.c_str()); 429 430 ofstream file(path.c_str(), ios::out | ios::binary); 431 432 m_pMemory->GetCurrentRule()->SaveRam(file); 433 434 Log("RAM saved"); 435 } 436} 437 438void GearboyCore::LoadRam() 439{ 440 LoadRam(NULL); 441} 442 443void GearboyCore::LoadRam(const char* szPath, bool fullPath) 444{ 445 if (m_pCartridge->IsLoadedROM() && m_pCartridge->HasBattery() && IsValidPointer(m_pMemory->GetCurrentRule())) 446 { 447 Log("Loading RAM..."); 448 449 using namespace std; 450 451 string sav_path = ""; 452 453 if (IsValidPointer(szPath)) 454 { 455 sav_path += szPath; 456 457 if (!fullPath) 458 { 459 sav_path += "/"; 460 sav_path += m_pCartridge->GetFileName(); 461 } 462 } 463 else 464 { 465 sav_path = m_pCartridge->GetFilePath(); 466 } 467 468 string rom_path = sav_path; 469 470 string::size_type i = sav_path.rfind('.', sav_path.length()); 471 472 if (i != string::npos) { 473 sav_path.replace(i + 1, 3, "sav"); 474 } 475 476 Log("Opening save file: %s", sav_path.c_str()); 477 478 ifstream file; 479 480 file.open(sav_path.c_str(), ios::in | ios::binary); 481 482 // check for old .gearboy saves 483 if (file.fail()) 484 { 485 Log("Save file doesn't exist"); 486 string old_sav_file = rom_path + ".gearboy"; 487 488 Log("Opening old save file: %s", old_sav_file.c_str()); 489 file.open(old_sav_file.c_str(), ios::in | ios::binary); 490 } 491 492 if (!file.fail()) 493 { 494 file.seekg(0, file.end); 495 s32 fileSize = (s32)file.tellg(); 496 file.seekg(0, file.beg); 497 498 if (m_pMemory->GetCurrentRule()->LoadRam(file, fileSize)) 499 { 500 Log("RAM loaded"); 501 } 502 else 503 { 504 Log("Save file size incorrect: %d", fileSize); 505 } 506 } 507 else 508 { 509 Log("Save file doesn't exist"); 510 } 511 } 512} 513 514void GearboyCore::SaveState(int index) 515{ 516 if (m_pMemory->IsBootromRegistryEnabled()) 517 { 518 Log("Save states disabled when running bootrom"); 519 return; 520 } 521 522 Log("Creating save state %d...", index); 523 524 SaveState(NULL, index); 525 526 Log("Save state %d created", index); 527} 528 529void GearboyCore::SaveState(const char* szPath, int index) 530{ 531 if (m_pMemory->IsBootromRegistryEnabled()) 532 { 533 Log("Save states disabled when running bootrom"); 534 return; 535 } 536 537 Log("Saving state..."); 538 539 using namespace std; 540 541 size_t size; 542 SaveState(NULL, size); 543 544 u8* buffer = new u8[size]; 545 string path = ""; 546 547 if (IsValidPointer(szPath)) 548 { 549 path += szPath; 550 path += "/"; 551 path += m_pCartridge->GetFileName(); 552 } 553 else 554 { 555 path = m_pCartridge->GetFilePath(); 556 } 557 558 string::size_type i = path.rfind('.', path.length()); 559 560 if (i != string::npos) { 561 path.replace(i + 1, 3, "state"); 562 } 563 564 std::stringstream sstm; 565 566 if (index < 0) 567 sstm << szPath; 568 else 569 sstm << path << index; 570 571 Log("Save state file: %s", sstm.str().c_str()); 572 573 ofstream file(sstm.str().c_str(), ios::out | ios::binary); 574 575 SaveState(file, size); 576 577 SafeDeleteArray(buffer); 578 579 file.close(); 580 581 Log("Save state created"); 582} 583 584bool GearboyCore::SaveState(u8* buffer, size_t& size) 585{ 586 if (m_pMemory->IsBootromRegistryEnabled()) 587 { 588 Log("Save states disabled when running bootrom"); 589 return false; 590 } 591 592 bool ret = false; 593 594 if (m_pCartridge->IsLoadedROM() && IsValidPointer(m_pMemory->GetCurrentRule())) 595 { 596 using namespace std; 597 598 stringstream stream; 599 600 if (SaveState(stream, size)) 601 ret = true; 602 603 if (IsValidPointer(buffer)) 604 { 605 Log("Saving state to buffer [%d bytes]...", size); 606 memcpy(buffer, stream.str().c_str(), size); 607 ret = true; 608 } 609 } 610 else 611 { 612 Log("Invalid rom or memory rule."); 613 } 614 615 return ret; 616} 617 618bool GearboyCore::SaveState(std::ostream& stream, size_t& size) 619{ 620 if (m_pMemory->IsBootromRegistryEnabled()) 621 { 622 Log("Save states disabled when running bootrom"); 623 return false; 624 } 625 626 if (m_pCartridge->IsLoadedROM() && IsValidPointer(m_pMemory->GetCurrentRule())) 627 { 628 Log("Gathering save state data..."); 629 630 using namespace std; 631 632 m_pMemory->SaveState(stream); 633 m_pProcessor->SaveState(stream); 634 m_pVideo->SaveState(stream); 635 m_pInput->SaveState(stream); 636 m_pAudio->SaveState(stream); 637 m_pMemory->GetCurrentRule()->SaveState(stream); 638 639 size = static_cast<size_t>(stream.tellp()); 640 641 size += (sizeof(u32) * 2); 642 643 u32 header_magic = SAVESTATE_MAGIC; 644 u32 header_size = static_cast<u32>(size); 645 646 stream.write(reinterpret_cast<const char*> (&header_magic), sizeof(header_magic)); 647 stream.write(reinterpret_cast<const char*> (&header_size), sizeof(header_size)); 648 649 Log("Save state size: %d", static_cast<size_t>(stream.tellp())); 650 651 return true; 652 } 653 654 Log("Invalid rom or memory rule."); 655 656 return false; 657} 658 659void GearboyCore::LoadState(int index) 660{ 661 if (m_pMemory->IsBootromRegistryEnabled()) 662 { 663 Log("Save states disabled when running bootrom"); 664 return; 665 } 666 667 Log("Loading save state %d...", index); 668 669 LoadState(NULL, index); 670 671 Log("State %d file loaded", index); 672} 673 674void GearboyCore::LoadState(const char* szPath, int index) 675{ 676 if (m_pMemory->IsBootromRegistryEnabled()) 677 { 678 Log("Save states disabled when running bootrom"); 679 return; 680 } 681 682 Log("Loading save state..."); 683 684 using namespace std; 685 686 string sav_path = ""; 687 688 if (IsValidPointer(szPath)) 689 { 690 sav_path += szPath; 691 sav_path += "/"; 692 sav_path += m_pCartridge->GetFileName(); 693 } 694 else 695 { 696 sav_path = m_pCartridge->GetFilePath(); 697 } 698 699 string rom_path = sav_path; 700 701 string::size_type i = sav_path.rfind('.', sav_path.length()); 702 703 if (i != string::npos) { 704 sav_path.replace(i + 1, 3, "state"); 705 } 706 707 std::stringstream sstm; 708 709 if (index < 0) 710 sstm << szPath; 711 else 712 sstm << sav_path << index; 713 714 Log("Opening save file: %s", sstm.str().c_str()); 715 716 ifstream file; 717 718 file.open(sstm.str().c_str(), ios::in | ios::binary); 719 720 if (!file.fail()) 721 { 722 if (LoadState(file)) 723 { 724 Log("Save state loaded"); 725 } 726 } 727 else 728 { 729 Log("Save state file doesn't exist"); 730 } 731 732 file.close(); 733} 734 735bool GearboyCore::LoadState(const u8* buffer, size_t size) 736{ 737 if (m_pMemory->IsBootromRegistryEnabled()) 738 { 739 Log("Save states disabled when running bootrom"); 740 return false; 741 } 742 743 if (m_pCartridge->IsLoadedROM() && IsValidPointer(m_pMemory->GetCurrentRule()) && (size > 0) && IsValidPointer(buffer)) 744 { 745 Log("Gathering load state data [%d bytes]...", size); 746 747 using namespace std; 748 749 stringstream stream; 750 751 stream.write(reinterpret_cast<const char*> (buffer), size); 752 753 return LoadState(stream); 754 } 755 756 Log("Invalid rom or memory rule."); 757 758 return false; 759} 760 761bool GearboyCore::LoadState(std::istream& stream) 762{ 763 if (m_pMemory->IsBootromRegistryEnabled()) 764 { 765 Log("Save states disabled when running bootrom"); 766 return false; 767 } 768 769 if (m_pCartridge->IsLoadedROM() && IsValidPointer(m_pMemory->GetCurrentRule())) 770 { 771 using namespace std; 772 773 u32 header_magic = 0; 774 u32 header_size = 0; 775 776 stream.seekg(0, ios::end); 777 size_t size = static_cast<size_t>(stream.tellg()); 778 779 Log("Load state stream size: %d", size); 780 781 stream.seekg(size - (2 * sizeof(u32)), ios::beg); 782 stream.read(reinterpret_cast<char*> (&header_magic), sizeof(header_magic)); 783 stream.read(reinterpret_cast<char*> (&header_size), sizeof(header_size)); 784 stream.seekg(0, ios::beg); 785 786 Log("Load state magic: 0x%08x", header_magic); 787 Log("Load state size: %d", header_size); 788 789 if ((header_size == size) && (header_magic == SAVESTATE_MAGIC)) 790 { 791 Log("Loading state..."); 792 793 m_pMemory->LoadState(stream); 794 m_pProcessor->LoadState(stream); 795 m_pVideo->LoadState(stream); 796 m_pInput->LoadState(stream); 797 m_pAudio->LoadState(stream); 798 m_pMemory->GetCurrentRule()->LoadState(stream); 799 800 return true; 801 } 802 else 803 { 804 Log("Invalid save state size"); 805 } 806 } 807 else 808 { 809 Log("Invalid rom or memory rule"); 810 } 811 812 return false; 813} 814 815void GearboyCore::SetCheat(const char* szCheat) 816{ 817 std::string s = szCheat; 818 if ((s.length() == 7) || (s.length() == 11)) 819 { 820 m_pCartridge->SetGameGenieCheat(szCheat); 821 if (m_pCartridge->IsLoadedROM()) 822 m_pMemory->LoadBank0and1FromROM(m_pCartridge->GetTheROM()); 823 } 824 else 825 { 826 m_pProcessor->SetGameSharkCheat(szCheat); 827 } 828} 829 830void GearboyCore::ClearCheats() 831{ 832 m_pCartridge->ClearGameGenieCheats(); 833 m_pProcessor->ClearGameSharkCheats(); 834 if (m_pCartridge->IsLoadedROM()) 835 m_pMemory->LoadBank0and1FromROM(m_pCartridge->GetTheROM()); 836} 837 838void GearboyCore::SetRamModificationCallback(RamChangedCallback callback) 839{ 840 m_pRamChangedCallback = callback; 841} 842 843bool GearboyCore::IsCGB() 844{ 845 return m_bCGB; 846} 847 848bool GearboyCore::IsGBA() 849{ 850 return m_bGBA; 851} 852 853void GearboyCore::InitDMGPalette() 854{ 855 GB_Color color[4]; 856 857 color[0].red = 0x87; 858 color[0].green = 0x96; 859 color[0].blue = 0x03; 860 861 color[1].red = 0x4d; 862 color[1].green = 0x6b; 863 color[1].blue = 0x03; 864 865 color[2].red = 0x2b; 866 color[2].green = 0x55; 867 color[2].blue = 0x03; 868 869 color[3].red = 0x14; 870 color[3].green = 0x44; 871 color[3].blue = 0x03; 872 873 SetDMGPalette(color[0], color[1], color[2], color[3]); 874} 875 876void GearboyCore::InitMemoryRules() 877{ 878 m_pIORegistersMemoryRule = new IORegistersMemoryRule(m_pProcessor, m_pMemory, m_pVideo, m_pInput, m_pAudio); 879 880 m_pCommonMemoryRule = new CommonMemoryRule(m_pMemory); 881 882 m_pRomOnlyMemoryRule = new RomOnlyMemoryRule(m_pProcessor, m_pMemory, 883 m_pVideo, m_pInput, m_pCartridge, m_pAudio); 884 885 m_pMBC1MemoryRule = new MBC1MemoryRule(m_pProcessor, m_pMemory, 886 m_pVideo, m_pInput, m_pCartridge, m_pAudio); 887 888 m_pMultiMBC1MemoryRule = new MultiMBC1MemoryRule(m_pProcessor, m_pMemory, 889 m_pVideo, m_pInput, m_pCartridge, m_pAudio); 890 891 m_pMBC2MemoryRule = new MBC2MemoryRule(m_pProcessor, m_pMemory, 892 m_pVideo, m_pInput, m_pCartridge, m_pAudio); 893 894 m_pMBC3MemoryRule = new MBC3MemoryRule(m_pProcessor, m_pMemory, 895 m_pVideo, m_pInput, m_pCartridge, m_pAudio); 896 897 m_pMBC5MemoryRule = new MBC5MemoryRule(m_pProcessor, m_pMemory, 898 m_pVideo, m_pInput, m_pCartridge, m_pAudio); 899 900 m_pMemory->SetCurrentRule(m_pRomOnlyMemoryRule); 901 m_pMemory->SetIORule(m_pIORegistersMemoryRule); 902 m_pMemory->SetCommonRule(m_pCommonMemoryRule); 903} 904 905bool GearboyCore::AddMemoryRules(Cartridge::CartridgeTypes forceType) 906{ 907 m_pMemory->SetIORule(m_pIORegistersMemoryRule); 908 m_pMemory->SetCommonRule(m_pCommonMemoryRule); 909 910 Cartridge::CartridgeTypes type = m_pCartridge->GetType(); 911 912 bool notSupported = false; 913 914 if (forceType != Cartridge::CartridgeNotSupported) 915 type = forceType; 916 917 switch (type) 918 { 919 case Cartridge::CartridgeNoMBC: 920 m_pMemory->SetCurrentRule(m_pRomOnlyMemoryRule); 921 break; 922 case Cartridge::CartridgeMBC1: 923 m_pMemory->SetCurrentRule(m_pMBC1MemoryRule); 924 break; 925 case Cartridge::CartridgeMBC1Multi: 926 m_pMemory->SetCurrentRule(m_pMultiMBC1MemoryRule); 927 break; 928 case Cartridge::CartridgeMBC2: 929 m_pMemory->SetCurrentRule(m_pMBC2MemoryRule); 930 break; 931 case Cartridge::CartridgeMBC3: 932 m_pMemory->SetCurrentRule(m_pMBC3MemoryRule); 933 break; 934 case Cartridge::CartridgeMBC5: 935 m_pMemory->SetCurrentRule(m_pMBC5MemoryRule); 936 break; 937 case Cartridge::CartridgeNotSupported: 938 notSupported = true; 939 break; 940 default: 941 notSupported = true; 942 } 943 944 if (!notSupported) 945 { 946 m_pMemory->GetCurrentRule()->SetRamChangedCallback(m_pRamChangedCallback); 947 } 948 949 return !notSupported; 950} 951 952void GearboyCore::Reset(bool bCGB, bool bGBA) 953{ 954 m_bCGB = bCGB; 955 m_bGBA = bGBA; 956 957 if (m_bGBA && m_bCGB) 958 { 959 Log("Reset: Switching to Game Boy Advance"); 960 } 961 else if (m_bCGB) 962 { 963 Log("Reset: Switching to Game Boy Color"); 964 } 965 else 966 { 967 Log("Reset: Defaulting to Game Boy DMG"); 968 } 969 970 m_pMemory->Reset(m_bCGB); 971 m_pProcessor->Reset(m_bCGB, m_bGBA); 972 m_pVideo->Reset(m_bCGB); 973 m_pAudio->Reset(m_bCGB); 974 m_pInput->Reset(); 975 m_pCartridge->UpdateCurrentRTC(); 976 m_iRTCUpdateCount = 0; 977 978 m_pCommonMemoryRule->Reset(m_bCGB); 979 m_pRomOnlyMemoryRule->Reset(m_bCGB); 980 m_pMBC1MemoryRule->Reset(m_bCGB); 981 m_pMultiMBC1MemoryRule->Reset(m_bCGB); 982 m_pMBC2MemoryRule->Reset(m_bCGB); 983 m_pMBC3MemoryRule->Reset(m_bCGB); 984 m_pMBC5MemoryRule->Reset(m_bCGB); 985 m_pIORegistersMemoryRule->Reset(m_bCGB); 986 987 m_bPaused = false; 988} 989 990void GearboyCore::RenderDMGFrame(u16* pFrameBuffer) const 991{ 992 if (IsValidPointer(pFrameBuffer)) 993 { 994 int pixels = GAMEBOY_WIDTH * GAMEBOY_HEIGHT; 995 const u8* pGameboyFrameBuffer = m_pVideo->GetFrameBuffer(); 996 997 for (int i = 0; i < pixels; i++) 998 { 999 pFrameBuffer[i] = m_DMGPalette[pGameboyFrameBuffer[i]]; 1000 } 1001 } 1002}