#include "addressSpace.hpp" void AddressSpace::determineMBCInfo() { MBC = static_cast(memoryLayout.romBank0[0x147]); romSize = 32768 * (1 << memoryLayout.romBank0[0x147]); romBanks = 1 << (memoryLayout.romBank0[0x147] + 1); const Byte ramSize = memoryLayout.romBank0[0x0149]; switch (ramSize) { case 0x02: externalRamSize = 8196; externalRamBanks = 1; break; case 0x03: externalRamSize = 32768; externalRamBanks = 4; break; case 0x04: externalRamSize = 131072; externalRamBanks = 16; break; case 0x05: externalRamSize = 65536; externalRamBanks = 8; break; default: externalRamSize = 0; externalRamBanks = 0; break; } if (MBC == MBC2 || MBC == MBC2Battery) { // only the lower 4 bits are usable externalRamSize = 512; } } bool AddressSpace::MBCWrite(const Word address) { if (address <= 0x7FFF) return true; return false; } Byte *AddressSpace::MBCRead(const Word address) { if (MBC == MBC1) { if (address <= 0x1FFF) return &ramEnable; if (address <= 0x3FFF) return &romBankRegister; if (address <= 0x5FFF) return &twoBitBankRegister; if (address <= 0x7FFF) return &romRamSelect; } if (MBC == MBC1Ram || MBC == MBC1RamBattery) { if (address <= 0x1FFF) return &ramEnable; // bits 0-4 if (address <= 0x3FFF) return &romBankRegister; if (address <= 0x5FFF) { return &twoBitBankRegister; } if (address <= 0x7FFF) return &romRamSelect; } if (MBC == MBC2 || MBC == MBC2Battery) { if (address <= 0x3FFF) { if (address & 0x0100) return &romBankRegister; else return &ramEnable; } } return &dummyVal; } void AddressSpace::MBCUpdate() { // TODO: multicart roms need to be able to switch the first rom bank as well // see: https://gbdev.io/pandocs/MBC1.html if (MBC == MBC1) { // Selected ROM Bank = (Secondary Bank << 5) + ROM Bank romBankRegister &= 0b11111; twoBitBankRegister &= 0b11; // 512 KiB can only have 8KiB of ram if (romSize >= 524288) { if (romBankRegister == 0) selectedRomBank = (twoBitBankRegister << 5) + 1; selectedRomBank = (twoBitBankRegister << 5) + romBankRegister; } else { if (romBankRegister == 0) selectedRomBank = 1; else selectedRomBank = romBankRegister; } if (romBankRegister == 0x20 || romBankRegister == 0x40 || romBankRegister == 0x60) romBankRegister += 1; selectedExternalRamBank = 0; loadRomBank(); loadRamBank(); } else if (MBC == MBC1Ram || MBC == MBC1RamBattery) { // Selected ROM Bank = (Secondary Bank << 5) + ROM Bank romBankRegister &= 0b11111; twoBitBankRegister &= 0b11; // 512 KiB can only have 8KiB of ram if (romSize >= 524288) { if (romBankRegister == 0) selectedRomBank = (twoBitBankRegister << 5) + 1; selectedRomBank = (twoBitBankRegister << 5) + romBankRegister; selectedExternalRamBank = 0; } else { if (romBankRegister == 0) selectedRomBank = 1; else selectedRomBank = romBankRegister; selectedExternalRamBank = twoBitBankRegister; } if (romBankRegister == 0x20 || romBankRegister == 0x40 || romBankRegister == 0x60) romBankRegister += 1; loadRomBank(); loadRamBank(); } else if (MBC == MBC2 || MBC == MBC2Battery) { selectedRomBank = romBankRegister & 0x0F; loadRomBank(); loadRamBank(); } else if (MBC == MBC3 || MBC == MBC3TimerBattery) { romBankRegister &= 0b11111; twoBitBankRegister &= 0b11; // 512 KiB can only have 8KiB of ram if (romSize >= 524288) { if (romBankRegister == 0) selectedRomBank = (twoBitBankRegister << 5) + 1; selectedRomBank = (twoBitBankRegister << 5) + romBankRegister; } else { if (romBankRegister == 0) selectedRomBank = 1; else selectedRomBank = romBankRegister; } } else if (MBC == MBC3Ram || MBC == MBC3RamBattery || MBC == MBC3TimerRamBattery) { romBankRegister &= 0b11111; twoBitBankRegister &= 0b11; // 512 KiB can only have 8KiB of ram if (romSize >= 524288) { if (romBankRegister == 0) selectedRomBank = (twoBitBankRegister << 5) + 1; selectedRomBank = (twoBitBankRegister << 5) + romBankRegister; selectedExternalRamBank = 0; } else { if (romBankRegister == 0) selectedRomBank = 1; else selectedRomBank = romBankRegister; selectedExternalRamBank = twoBitBankRegister; } } } void AddressSpace::loadRomBank() { memoryLayout.romBankSwitch = game.data() + (ROM_BANK_SIZE * selectedRomBank); } void AddressSpace::createRamBank() { if (externalRamSize) { cartridgeRam = new Byte[externalRamSize]; memoryLayout.externalRam = cartridgeRam; } } void AddressSpace::loadRamBank() { if (cartridgeRam != nullptr) { memoryLayout.externalRam = cartridgeRam + (RAM_BANK_SIZE * selectedExternalRamBank); } }