cscg22-gearboy

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

MBC5MemoryRule.cpp (7267B)


      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 "MBC5MemoryRule.h"
     21#include "Video.h"
     22#include "Memory.h"
     23#include "Processor.h"
     24#include "Input.h"
     25#include "Cartridge.h"
     26
     27MBC5MemoryRule::MBC5MemoryRule(Processor* pProcessor,
     28        Memory* pMemory, Video* pVideo, Input* pInput,
     29        Cartridge* pCartridge, Audio* pAudio) : MemoryRule(pProcessor,
     30pMemory, pVideo, pInput, pCartridge, pAudio)
     31{
     32    m_pRAMBanks = new u8[0x20000];
     33    Reset(false);
     34}
     35
     36MBC5MemoryRule::~MBC5MemoryRule()
     37{
     38    SafeDeleteArray(m_pRAMBanks);
     39}
     40
     41void MBC5MemoryRule::Reset(bool bCGB)
     42{
     43    m_bCGB = bCGB;
     44    m_iCurrentRAMBank = 0;
     45    m_iCurrentROMBank = 1;
     46    m_iCurrentROMBankHi = 0;
     47    m_bRamEnabled = false;
     48    for (int i = 0; i < 0x20000; i++)
     49        m_pRAMBanks[i] = 0xFF;
     50    m_CurrentROMAddress = 0x4000;
     51    m_CurrentRAMAddress = 0;
     52}
     53
     54u8 MBC5MemoryRule::PerformRead(u16 address)
     55{
     56    switch (address & 0xE000)
     57    {
     58        case 0x4000:
     59        case 0x6000:
     60        {
     61            u8* pROM = m_pCartridge->GetTheROM();
     62            return pROM[(address - 0x4000) + m_CurrentROMAddress];
     63        }
     64        case 0xA000:
     65        {
     66            if (m_bRamEnabled)
     67            {
     68                return m_pRAMBanks[(address - 0xA000) + m_CurrentRAMAddress];
     69            }
     70            else
     71            {
     72                Log("--> ** Attempting to read from disabled ram %X", address);
     73                return 0xFF;
     74            }
     75        }
     76        default:
     77        {
     78            return m_pMemory->Retrieve(address);
     79        }
     80    }
     81}
     82
     83void MBC5MemoryRule::PerformWrite(u16 address, u8 value)
     84{
     85    switch (address & 0xE000)
     86    {
     87        case 0x0000:
     88        {
     89            if (m_pCartridge->GetRAMSize() > 0)
     90            {
     91                bool previous = m_bRamEnabled;
     92                m_bRamEnabled = ((value & 0x0F) == 0x0A);
     93
     94                if (IsValidPointer(m_pRamChangedCallback) && previous && !m_bRamEnabled)
     95                {
     96                    (*m_pRamChangedCallback)();
     97                }
     98            }
     99            break;
    100        }
    101        case 0x2000:
    102        {
    103            if (address < 0x3000)
    104            {
    105                m_iCurrentROMBank = value | (m_iCurrentROMBankHi << 8);
    106            }
    107            else
    108            {
    109                m_iCurrentROMBankHi = value & 0x01;
    110                m_iCurrentROMBank = (m_iCurrentROMBank & 0xFF) | (m_iCurrentROMBankHi << 8);
    111            }
    112            m_iCurrentROMBank &= (m_pCartridge->GetROMBankCount() - 1);
    113            m_CurrentROMAddress = m_iCurrentROMBank * 0x4000;
    114            break;
    115        }
    116        case 0x4000:
    117        {
    118            m_iCurrentRAMBank = value & 0x0F;
    119            m_iCurrentRAMBank &= (m_pCartridge->GetRAMBankCount() - 1);
    120            m_CurrentRAMAddress = m_iCurrentRAMBank * 0x2000;
    121            break;
    122        }
    123        case 0x6000:
    124        {
    125            Log("--> ** Attempting to write on invalid address %X %X", address, value);
    126            break;
    127        }
    128        case 0xA000:
    129        {
    130            if (m_bRamEnabled)
    131            {
    132                m_pRAMBanks[(address - 0xA000) + m_CurrentRAMAddress] = value;
    133            }
    134            else
    135            {
    136                Log("--> ** Attempting to write on RAM when ram is disabled %X %X", address, value);
    137            }
    138            break;
    139        }
    140        default:
    141        {
    142            m_pMemory->Load(address, value);
    143            break;
    144        }
    145    }
    146}
    147
    148void MBC5MemoryRule::SaveRam(std::ostream & file)
    149{
    150    Log("MBC5MemoryRule save RAM...");
    151    Log("MBC5MemoryRule saving %d banks...", m_pCartridge->GetRAMBankCount());
    152
    153    s32 ramSize = m_pCartridge->GetRAMBankCount() * 0x2000;
    154
    155    for (s32 i = 0; i < ramSize; i++)
    156    {
    157        u8 ram_byte = m_pRAMBanks[i];
    158        file.write(reinterpret_cast<const char*> (&ram_byte), 1);
    159    }
    160
    161    Log("MBC5MemoryRule save RAM done");
    162}
    163
    164bool MBC5MemoryRule::LoadRam(std::istream & file, s32 fileSize)
    165{
    166    Log("MBC5MemoryRule load RAM...");
    167    Log("MBC5MemoryRule loading %d banks...", m_pCartridge->GetRAMBankCount());
    168
    169    s32 ramSize = m_pCartridge->GetRAMBankCount() * 0x2000;
    170
    171    if ((fileSize > 0) && (fileSize != ramSize))
    172    {
    173        Log("MBC5MemoryRule incorrect size. Expected: %d Found: %d", ramSize, fileSize);
    174        return false;
    175    }
    176
    177    for (s32 i = 0; i < ramSize; i++)
    178    {
    179        u8 ram_byte = 0;
    180        file.read(reinterpret_cast<char*> (&ram_byte), 1);
    181        m_pRAMBanks[i] = ram_byte;
    182    }
    183
    184    Log("MBC5MemoryRule load RAM done");
    185
    186    return true;
    187}
    188
    189size_t MBC5MemoryRule::GetRamSize()
    190{
    191    return m_pCartridge->GetRAMBankCount() * 0x2000;
    192}
    193
    194u8* MBC5MemoryRule::GetRamBanks()
    195{
    196    return m_pRAMBanks;
    197}
    198
    199u8* MBC5MemoryRule::GetCurrentRamBank()
    200{
    201    return m_pRAMBanks + m_CurrentRAMAddress;
    202}
    203
    204int MBC5MemoryRule::GetCurrentRamBankIndex()
    205{
    206    return m_iCurrentRAMBank;
    207}
    208
    209u8* MBC5MemoryRule::GetRomBank0()
    210{
    211    return m_pMemory->GetMemoryMap() + 0x0000;
    212}
    213
    214int MBC5MemoryRule::GetCurrentRomBank0Index()
    215{
    216    return 0;
    217}
    218
    219u8* MBC5MemoryRule::GetCurrentRomBank1()
    220{
    221    u8* pROM = m_pCartridge->GetTheROM();
    222    return &pROM[m_CurrentROMAddress];
    223}
    224
    225int MBC5MemoryRule::GetCurrentRomBank1Index()
    226{
    227    return m_iCurrentROMBank;
    228}
    229
    230void MBC5MemoryRule::SaveState(std::ostream& stream)
    231{
    232    using namespace std;
    233
    234    stream.write(reinterpret_cast<const char*> (&m_iCurrentRAMBank), sizeof(m_iCurrentRAMBank));
    235    stream.write(reinterpret_cast<const char*> (&m_iCurrentROMBank), sizeof(m_iCurrentROMBank));
    236    stream.write(reinterpret_cast<const char*> (&m_iCurrentROMBankHi), sizeof(m_iCurrentROMBankHi));
    237    stream.write(reinterpret_cast<const char*> (&m_bRamEnabled), sizeof(m_bRamEnabled));
    238    stream.write(reinterpret_cast<const char*> (m_pRAMBanks), 0x20000);
    239    stream.write(reinterpret_cast<const char*> (&m_CurrentROMAddress), sizeof(m_CurrentROMAddress));
    240    stream.write(reinterpret_cast<const char*> (&m_CurrentRAMAddress), sizeof(m_CurrentRAMAddress));
    241}
    242
    243void MBC5MemoryRule::LoadState(std::istream& stream)
    244{
    245    using namespace std;
    246
    247    stream.read(reinterpret_cast<char*> (&m_iCurrentRAMBank), sizeof(m_iCurrentRAMBank));
    248    stream.read(reinterpret_cast<char*> (&m_iCurrentROMBank), sizeof(m_iCurrentROMBank));
    249    stream.read(reinterpret_cast<char*> (&m_iCurrentROMBankHi), sizeof(m_iCurrentROMBankHi));
    250    stream.read(reinterpret_cast<char*> (&m_bRamEnabled), sizeof(m_bRamEnabled));
    251    stream.read(reinterpret_cast<char*> (m_pRAMBanks), 0x20000);
    252    stream.read(reinterpret_cast<char*> (&m_CurrentROMAddress), sizeof(m_CurrentROMAddress));
    253    stream.read(reinterpret_cast<char*> (&m_CurrentRAMAddress), sizeof(m_CurrentRAMAddress));
    254}