cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

Memory.cpp (18034B)


      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 <iostream>
     21#include <fstream>
     22#include "Memory.h"
     23#include "Processor.h"
     24#include "Video.h"
     25
     26Memory::Memory()
     27{
     28    InitPointer(m_pProcessor);
     29    InitPointer(m_pVideo);
     30    InitPointer(m_pMap);
     31    InitPointer(m_pDisassembledMap);
     32    InitPointer(m_pDisassembledROMMap);
     33    InitPointer(m_pWRAMBanks);
     34    InitPointer(m_pLCDRAMBank1);
     35    InitPointer(m_pCommonMemoryRule);
     36    InitPointer(m_pIORegistersMemoryRule);
     37    InitPointer(m_pCurrentMemoryRule);
     38    InitPointer(m_pBootromDMG);
     39    InitPointer(m_pBootromGBC);
     40    m_bCGB = false;
     41    m_iCurrentWRAMBank = 1;
     42    m_iCurrentLCDRAMBank = 0;
     43    m_bHDMAEnabled = false;
     44    m_iHDMABytes = 0;
     45    for (int i = 0; i < 5; i++)
     46        m_HDMA[i] = 0;
     47    m_HDMASource = 0;
     48    m_HDMADestination = 0;
     49    m_bBootromDMGEnabled = false;
     50    m_bBootromGBCEnabled = false;
     51    m_bBootromRegistryDisabled = false;
     52    m_bBootromDMGLoaded = false;
     53    m_bBootromGBCLoaded = false;
     54}
     55
     56Memory::~Memory()
     57{
     58    InitPointer(m_pProcessor);
     59    InitPointer(m_pVideo);
     60    SafeDeleteArray(m_pMap);
     61    SafeDeleteArray(m_pWRAMBanks);
     62    SafeDeleteArray(m_pLCDRAMBank1);
     63    InitPointer(m_pCommonMemoryRule);
     64    InitPointer(m_pIORegistersMemoryRule);
     65    InitPointer(m_pCurrentMemoryRule);
     66    SafeDeleteArray(m_pBootromDMG);
     67    SafeDeleteArray(m_pBootromGBC);
     68
     69    if (IsValidPointer(m_pDisassembledROMMap))
     70    {
     71        for (int i = 0; i < MAX_ROM_SIZE; i++)
     72        {
     73            SafeDelete(m_pDisassembledROMMap[i]);
     74        }
     75        SafeDeleteArray(m_pDisassembledROMMap);
     76    }
     77
     78    if (IsValidPointer(m_pDisassembledMap))
     79    {
     80        for (int i = 0; i < 65536; i++)
     81        {
     82            SafeDelete(m_pDisassembledMap[i]);
     83        }
     84        SafeDeleteArray(m_pDisassembledMap);
     85    }
     86}
     87
     88void Memory::SetProcessor(Processor* pProcessor)
     89{
     90    m_pProcessor = pProcessor;
     91}
     92
     93void Memory::SetVideo(Video* pVideo)
     94{
     95    m_pVideo = pVideo;
     96}
     97
     98void Memory::Init()
     99{
    100    m_pMap = new u8[65536];
    101    m_pWRAMBanks = new u8[0x8000];
    102    m_pLCDRAMBank1 = new u8[0x2000];
    103    m_pBootromDMG = new u8[0x100];
    104    m_pBootromGBC = new u8[0x900];
    105#ifndef GEARBOY_DISABLE_DISASSEMBLER
    106    m_pDisassembledMap = new stDisassembleRecord*[65536];
    107    for (int i = 0; i < 65536; i++)
    108    {
    109        InitPointer(m_pDisassembledMap[i]);
    110    }
    111
    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#endif
    118    m_BreakpointsCPU.clear();
    119    m_BreakpointsMem.clear();
    120    InitPointer(m_pRunToBreakpoint);
    121    Reset(false);
    122}
    123
    124void Memory::Reset(bool bCGB)
    125{
    126    m_bCGB = bCGB;
    127    InitPointer(m_pCommonMemoryRule);
    128    InitPointer(m_pIORegistersMemoryRule);
    129    InitPointer(m_pCurrentMemoryRule);
    130    m_iCurrentWRAMBank = 1;
    131    m_iCurrentLCDRAMBank = 0;
    132    m_bHDMAEnabled = false;
    133    m_iHDMABytes = 0;
    134    m_bBootromRegistryDisabled = false;
    135
    136    if (IsBootromEnabled())
    137        ResetBootromDisassembledMemory();
    138
    139    for (int i = 0; i < 65536; i++)
    140    {
    141        m_pMap[i] = 0x00;
    142
    143        if ((i >= 0x8000) && (i < 0xA000))
    144        {
    145            m_pMap[i] = 0x00;
    146            m_pLCDRAMBank1[i - 0x8000] = 0x00;
    147        }
    148        else if ((i >= 0xC000) && (i < 0xE000))
    149        {
    150            if ((i & 0x8) ^((i & 0x800) >> 8))
    151            {
    152                if (m_bCGB)
    153                {
    154                    m_pMap[i] = 0x00;
    155                    if (i >= 0xD000)
    156                    {
    157                        for (int a = 0; a < 8; a++)
    158                        {
    159                            if (a != 2)
    160                                m_pWRAMBanks[(i - 0xD000) + (0x1000 * a)] = m_pMap[i - 0x1000];
    161                            else
    162                                m_pWRAMBanks[(i - 0xD000) + (0x1000 * a)] = 0x00;
    163                        }
    164                    }
    165                }
    166                else
    167                    m_pMap[i] = 0x0f;
    168            }
    169            else
    170            {
    171                m_pMap[i] = 0xff;
    172                if (i >= 0xD000)
    173                {
    174                    for (int a = 0; a < 8; a++)
    175                    {
    176                        if (a != 2)
    177                            m_pWRAMBanks[(i - 0xD000) + (0x1000 * a)] = m_pMap[i - 0x1000];
    178                        else
    179                            m_pWRAMBanks[(i - 0xD000) + (0x1000 * a)] = 0x00;
    180                    }
    181                }
    182            }
    183        }
    184        else if (i >= 0xFF00)
    185        {
    186            if (m_bCGB)
    187                m_pMap[i] = kInitialValuesForColorFFXX[i - 0xFF00];
    188            else
    189                m_pMap[i] = kInitialValuesForFFXX[i - 0xFF00];
    190        }
    191        else
    192        {
    193            m_pMap[i] = 0xFF;
    194        }
    195    }
    196
    197    if (m_bCGB)
    198    {
    199        for (int i = 0; i < 5; i++)
    200        {
    201            m_HDMA[i] = m_pMap[0xFF51 + i];
    202        }
    203
    204        u8 hdma1 = m_HDMA[0];
    205        u8 hdma2 = m_HDMA[1];
    206        u8 hdma3 = m_HDMA[2];
    207        u8 hdma4 = m_HDMA[3];
    208
    209        if (hdma1 > 0x7f && hdma1 < 0xa0)
    210            hdma1 = 0;
    211
    212        m_HDMASource = (hdma1 << 8) | (hdma2 & 0xF0);
    213        m_HDMADestination = ((hdma3 & 0x1F) << 8) | (hdma4 & 0xF0);
    214        m_HDMADestination |= 0x8000;
    215    }
    216}
    217
    218void Memory::SetCurrentRule(MemoryRule* pRule)
    219{
    220    m_pCurrentMemoryRule = pRule;
    221}
    222
    223void Memory::SetCommonRule(CommonMemoryRule* pRule)
    224{
    225    m_pCommonMemoryRule = pRule;
    226}
    227
    228void Memory::SetIORule(IORegistersMemoryRule* pRule)
    229{
    230    m_pIORegistersMemoryRule = pRule;
    231}
    232
    233MemoryRule* Memory::GetCurrentRule()
    234{
    235    return m_pCurrentMemoryRule;
    236}
    237
    238u8* Memory::GetMemoryMap()
    239{
    240    return m_pMap;
    241}
    242
    243void Memory::LoadBank0and1FromROM(u8* pTheROM)
    244{
    245    // loads the first 32KB only (bank 0 and 1)
    246    for (int i = 0; i < 0x8000; i++)
    247    {
    248        m_pMap[i] = pTheROM[i];
    249    }
    250}
    251
    252void Memory::MemoryDump(const char* szFilePath)
    253{
    254    if (!IsValidPointer(m_pDisassembledMap))
    255        return;
    256
    257    using namespace std;
    258
    259    ofstream myfile(szFilePath, ios::out | ios::trunc);
    260
    261    if (myfile.is_open())
    262    {
    263        for (int i = 0; i < 65536; i++)
    264        {
    265            if (IsValidPointer(m_pDisassembledMap[i]) && (m_pDisassembledMap[i]->name[0] != 0))
    266            {
    267                myfile << "0x" << hex << i << "\t " << m_pDisassembledMap[i]->name << "\n";
    268                i += (m_pDisassembledMap[i]->size - 1);
    269            }
    270            else
    271            {
    272                myfile << "0x" << hex << i << "\t [0x" << hex << (int) m_pMap[i] << "]\n";
    273            }
    274        }
    275
    276        myfile.close();
    277    }
    278}
    279
    280void Memory::PerformDMA(u8 value)
    281{
    282    if (m_bCGB)
    283    {
    284        u16 address = value << 8;
    285        if (address < 0xE000)
    286        {
    287            if (address >= 0x8000 && address < 0xA000)
    288            {
    289                for (int i = 0; i < 0xA0; i++)
    290                    Load(0xFE00 + i, ReadCGBLCDRAM(address + i, false));
    291            }
    292            else if (address >= 0xD000 && address < 0xE000)
    293            {
    294                for (int i = 0; i < 0xA0; i++)
    295                    Load(0xFE00 + i, ReadCGBWRAM(address + i));
    296            }
    297            else
    298            {
    299                for (int i = 0; i < 0xA0; i++)
    300                    Load(0xFE00 + i, Read(address + i));
    301            }
    302        }
    303    }
    304    else
    305    {
    306        u16 address = value << 8;
    307        if (address >= 0x8000 && address < 0xE000)
    308        {
    309            for (int i = 0; i < 0xA0; i++)
    310                Load(0xFE00 + i, Read(address + i));
    311        }
    312    }
    313}
    314
    315void Memory::SwitchCGBDMA(u8 value)
    316{
    317    m_iHDMABytes = 16 + ((value & 0x7f) * 16);
    318
    319    if (m_bHDMAEnabled)
    320    {
    321        if (IsSetBit(value, 7))
    322        {
    323            m_HDMA[4] = value & 0x7F;
    324        }
    325        else
    326        {
    327            m_HDMA[4] = 0xFF;
    328            m_bHDMAEnabled = false;
    329        }
    330    }
    331    else
    332    {
    333        if (IsSetBit(value, 7))
    334        {
    335            m_bHDMAEnabled = true;
    336            m_HDMA[4] = value & 0x7F;
    337            if (m_pVideo->GetCurrentStatusMode() == 0)
    338            {
    339                m_pProcessor->AddCycles(PerformHDMA());
    340            }
    341        }
    342        else
    343        {
    344            PerformGDMA(value);
    345        }
    346    }
    347}
    348
    349unsigned int Memory::PerformHDMA()
    350{
    351    u16 source = m_HDMASource & 0xFFF0;
    352    u16 destination = (m_HDMADestination & 0x1FF0) | 0x8000;
    353
    354    if (source >= 0xD000 && source < 0xE000)
    355    {
    356        for (int i = 0; i < 0x10; i++)
    357            WriteCGBLCDRAM(destination + i, ReadCGBWRAM(source + i));
    358    }
    359    else
    360    {
    361        for (int i = 0; i < 0x10; i++)
    362            WriteCGBLCDRAM(destination + i, Read(source + i));
    363    }
    364
    365    m_HDMADestination += 0x10;
    366    if (m_HDMADestination == 0xA000)
    367        m_HDMADestination = 0x8000;
    368
    369    m_HDMASource += 0x10;
    370    if (m_HDMASource == 0x8000)
    371        m_HDMASource = 0xA000;
    372
    373    m_HDMA[1] = m_HDMASource & 0xFF;
    374    m_HDMA[0] = m_HDMASource >> 8;
    375
    376    m_HDMA[3] = m_HDMADestination & 0xFF;
    377    m_HDMA[2] = m_HDMADestination >> 8;
    378
    379    m_iHDMABytes -= 0x10;
    380    m_HDMA[4]--;
    381
    382    if (m_HDMA[4] == 0xFF)
    383        m_bHDMAEnabled = false;
    384
    385    // return clock cycles used
    386    return (m_pProcessor->CGBSpeed() ? 17 : 9) * 4;
    387}
    388
    389void Memory::PerformGDMA(u8 value)
    390{
    391    u16 source = m_HDMASource & 0xFFF0;
    392    u16 destination = (m_HDMADestination & 0x1FF0) | 0x8000;
    393
    394    if (source >= 0xD000 && source < 0xE000)
    395    {
    396        for (int i = 0; i < m_iHDMABytes; i++)
    397            WriteCGBLCDRAM(destination + i, ReadCGBWRAM(source + i));
    398    }
    399    else
    400    {
    401        for (int i = 0; i < m_iHDMABytes; i++)
    402            WriteCGBLCDRAM(destination + i, Read(source + i));
    403    }
    404
    405    m_HDMADestination += m_iHDMABytes;
    406    m_HDMASource += m_iHDMABytes;
    407
    408    for (int i = 0; i < 5; i++)
    409        m_HDMA[i] = 0xFF;
    410
    411    int clock_cycles = 0;
    412
    413    if (m_pProcessor->CGBSpeed())
    414        clock_cycles = 2 + 16 * ((value & 0x7f) + 1);
    415    else
    416        clock_cycles = 1 + 8 * ((value & 0x7f) + 1);
    417
    418    m_pProcessor->AddCycles(clock_cycles * 4);
    419}
    420
    421bool Memory::IsHDMAEnabled() const
    422{
    423    return m_bHDMAEnabled;
    424}
    425
    426void Memory::SetHDMARegister(int reg, u8 value)
    427{
    428    switch (reg)
    429    {
    430        case 1:
    431        {
    432            // HDMA1
    433            if (value > 0x7f && value < 0xa0)
    434                value = 0;
    435            m_HDMASource = (value << 8) | (m_HDMASource & 0xF0);
    436            break;
    437        }
    438        case 2:
    439        {
    440            // HDMA2
    441            value &= 0xF0;
    442            m_HDMASource = (m_HDMASource & 0xFF00) | value;
    443            break;
    444        }
    445        case 3:
    446        {
    447            // HDMA3
    448            value &= 0x1F;
    449            m_HDMADestination = (value << 8) | (m_HDMADestination & 0xF0);
    450            m_HDMADestination |= 0x8000;
    451            break;
    452        }
    453        case 4:
    454        {
    455            // HDMA4
    456            value &= 0xF0;
    457            m_HDMADestination = (m_HDMADestination & 0x1F00) | value;
    458            m_HDMADestination |= 0x8000;
    459            break;
    460        }
    461    }
    462
    463    m_HDMA[reg - 1] = value;
    464}
    465
    466u8 Memory::GetHDMARegister(int reg) const
    467{
    468    return m_HDMA[reg - 1];
    469}
    470
    471u8* Memory::GetCGBRAM()
    472{
    473    return m_pWRAMBanks;
    474}
    475
    476int Memory::GetCurrentCGBRAMBank()
    477{
    478    return m_iCurrentWRAMBank;
    479}
    480
    481int Memory::GetCurrentLCDRAMBank()
    482{
    483    return m_iCurrentLCDRAMBank;
    484}
    485
    486void Memory::SaveState(std::ostream& stream)
    487{
    488    using namespace std;
    489
    490    stream.write(reinterpret_cast<const char*> (m_pMap), 65536);
    491    stream.write(reinterpret_cast<const char*> (&m_iCurrentWRAMBank), sizeof(m_iCurrentWRAMBank));
    492    stream.write(reinterpret_cast<const char*> (&m_iCurrentLCDRAMBank), sizeof(m_iCurrentLCDRAMBank));
    493    stream.write(reinterpret_cast<const char*> (m_pWRAMBanks), 0x8000);
    494    stream.write(reinterpret_cast<const char*> (m_pLCDRAMBank1), 0x2000);
    495    stream.write(reinterpret_cast<const char*> (&m_bHDMAEnabled), sizeof(m_bHDMAEnabled));
    496    stream.write(reinterpret_cast<const char*> (&m_iHDMABytes), sizeof(m_iHDMABytes));
    497    stream.write(reinterpret_cast<const char*> (m_HDMA), sizeof(m_HDMA));
    498    stream.write(reinterpret_cast<const char*> (&m_HDMASource), sizeof(m_HDMASource));
    499    stream.write(reinterpret_cast<const char*> (&m_HDMADestination), sizeof(m_HDMADestination));
    500}
    501
    502void Memory::LoadState(std::istream& stream)
    503{
    504    using namespace std;
    505
    506    stream.read(reinterpret_cast<char*> (m_pMap), 65536);
    507    stream.read(reinterpret_cast<char*> (&m_iCurrentWRAMBank), sizeof(m_iCurrentWRAMBank));
    508    stream.read(reinterpret_cast<char*> (&m_iCurrentLCDRAMBank), sizeof(m_iCurrentLCDRAMBank));
    509    stream.read(reinterpret_cast<char*> (m_pWRAMBanks), 0x8000);
    510    stream.read(reinterpret_cast<char*> (m_pLCDRAMBank1), 0x2000);
    511    stream.read(reinterpret_cast<char*> (&m_bHDMAEnabled), sizeof(m_bHDMAEnabled));
    512    stream.read(reinterpret_cast<char*> (&m_iHDMABytes), sizeof(m_iHDMABytes));
    513    stream.read(reinterpret_cast<char*> (m_HDMA), sizeof(m_HDMA));
    514    stream.read(reinterpret_cast<char*> (&m_HDMASource), sizeof(m_HDMASource));
    515    stream.read(reinterpret_cast<char*> (&m_HDMADestination), sizeof(m_HDMADestination));
    516}
    517
    518u8* Memory::GetROM0()
    519{
    520    return m_pCurrentMemoryRule->GetRomBank0();
    521}
    522
    523u8* Memory::GetROM1()
    524{
    525    return m_pCurrentMemoryRule->GetCurrentRomBank1();
    526}
    527
    528u8* Memory::GetVRAM()
    529{
    530    if (m_bCGB)
    531        return (m_iCurrentLCDRAMBank == 1) ? m_pLCDRAMBank1 : m_pMap + 0x8000;
    532    else
    533        return m_pMap + 0x8000;
    534}
    535
    536u8* Memory::GetRAM()
    537{
    538    return m_pCurrentMemoryRule->GetCurrentRamBank();
    539}
    540
    541u8* Memory::GetWRAM0()
    542{
    543    return m_bCGB ? m_pWRAMBanks : m_pMap + 0xC000;
    544}
    545
    546u8* Memory::GetWRAM1()
    547{
    548    return m_bCGB ? m_pWRAMBanks + (0x1000 * m_iCurrentWRAMBank) : m_pMap + 0xD000;
    549}
    550
    551std::vector<Memory::stDisassembleRecord*>* Memory::GetBreakpointsCPU()
    552{
    553    return &m_BreakpointsCPU;
    554}
    555
    556std::vector<Memory::stMemoryBreakpoint>* Memory::GetBreakpointsMem()
    557{
    558    return &m_BreakpointsMem;
    559}
    560
    561Memory::stDisassembleRecord* Memory::GetRunToBreakpoint()
    562{
    563    return m_pRunToBreakpoint;
    564}
    565
    566void Memory::SetRunToBreakpoint(Memory::stDisassembleRecord* pBreakpoint)
    567{
    568    m_pRunToBreakpoint = pBreakpoint;
    569}
    570
    571void Memory::EnableBootromDMG(bool enable)
    572{
    573    m_bBootromDMGEnabled = enable;
    574
    575    if (m_bBootromDMGEnabled)
    576    {
    577        Log("DMG Bootrom enabled");
    578    }
    579    else
    580    {
    581        Log("DMG Bootrom disabled");
    582    }
    583}
    584
    585void Memory::EnableBootromGBC(bool enable)
    586{
    587    m_bBootromGBCEnabled = enable;
    588
    589    if (m_bBootromGBCEnabled)
    590    {
    591        Log("GBC Bootrom enabled");
    592    }
    593    else
    594    {
    595        Log("GBC Bootrom disabled");
    596    }
    597}
    598
    599void Memory::LoadBootromDMG(const char* szFilePath)
    600{
    601    Log("Loading DMG Bootrom %s...", szFilePath);
    602
    603    LoadBootroom(szFilePath, false);
    604}
    605
    606void Memory::LoadBootromGBC(const char* szFilePath)
    607{
    608    Log("Loading GBC Bootrom %s...", szFilePath);
    609
    610    LoadBootroom(szFilePath, true);
    611}
    612
    613bool Memory::IsBootromEnabled()
    614{
    615    return (m_bBootromDMGEnabled && m_bBootromDMGLoaded && !m_bCGB) || (m_bBootromGBCEnabled && m_bBootromGBCLoaded && m_bCGB);
    616}
    617
    618void Memory::DisableBootromRegistry()
    619{
    620    if (!m_bBootromRegistryDisabled && IsBootromEnabled())
    621    {
    622        ResetBootromDisassembledMemory();
    623    }
    624
    625    m_bBootromRegistryDisabled = true;
    626}
    627
    628bool Memory::IsBootromRegistryEnabled()
    629{
    630    return !m_bBootromRegistryDisabled;
    631}
    632
    633void Memory::ResetDisassembledMemory()
    634{
    635    #ifndef GEARBOY_DISABLE_DISASSEMBLER
    636
    637    if (IsValidPointer(m_pDisassembledROMMap))
    638    {
    639        for (int i = 0; i < MAX_ROM_SIZE; i++)
    640        {
    641            SafeDelete(m_pDisassembledROMMap[i]);
    642        }
    643    }
    644    if (IsValidPointer(m_pDisassembledMap))
    645    {
    646        for (int i = 0; i < 65536; i++)
    647        {
    648            SafeDelete(m_pDisassembledMap[i]);
    649        }
    650    }
    651
    652    #endif
    653}
    654
    655void Memory::ResetBootromDisassembledMemory()
    656{
    657    #ifndef GEARBOY_DISABLE_DISASSEMBLER
    658
    659    m_BreakpointsCPU.clear();
    660
    661    if (IsValidPointer(m_pDisassembledROMMap))
    662    {
    663        for (int i = 0; i < 0x0100; i++)
    664        {
    665            SafeDelete(m_pDisassembledROMMap[i]);
    666        }
    667    }
    668    if (IsValidPointer(m_pDisassembledMap))
    669    {
    670        for (int i = 0; i < 0x0100; i++)
    671        {
    672            SafeDelete(m_pDisassembledMap[i]);
    673        }
    674    }
    675
    676    if (m_bCGB)
    677    {
    678        if (IsValidPointer(m_pDisassembledROMMap))
    679        {
    680            for (int i = 0x0200; i < 0x0900; i++)
    681            {
    682                SafeDelete(m_pDisassembledROMMap[i]);
    683            }
    684        }
    685        if (IsValidPointer(m_pDisassembledMap))
    686        {
    687            for (int i = 0x0200; i < 0x0900; i++)
    688            {
    689                SafeDelete(m_pDisassembledMap[i]);
    690            }
    691        }
    692    }
    693
    694    #endif
    695}
    696
    697void Memory::LoadBootroom(const char* szFilePath, bool gbc)
    698{
    699    using namespace std;
    700
    701    int expectedSize = gbc ? 0x900 : 0x100;
    702    u8* bootrom = gbc ? m_pBootromGBC : m_pBootromDMG;
    703
    704    ifstream file(szFilePath, ios::in | ios::binary | ios::ate);
    705
    706    bool ret = false;
    707
    708    if (file.is_open())
    709    {
    710        int size = static_cast<int> (file.tellg());
    711
    712        if (size == expectedSize)
    713        {
    714            file.seekg(0, ios::beg);
    715            file.read(reinterpret_cast<char*>(bootrom), size);
    716            file.close();
    717
    718            ret = true;
    719
    720            Log("Bootrom %s loaded", szFilePath);
    721        }
    722        else
    723        {
    724            Log("Incompatible bootrom size (expected 0x%X): 0x%X", expectedSize, size);
    725        }
    726    }
    727    else
    728    {
    729        Log("There was a problem opening the file %s", szFilePath);
    730    }
    731
    732    if (gbc)
    733        m_bBootromGBCLoaded = ret;
    734    else
    735        m_bBootromDMGLoaded = ret;
    736}