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