using System; using System.Collections.Generic; using System.Linq; using BizHawk.Common; namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge { public abstract partial class CartridgeDevice { private sealed class Mapper0005 : CartridgeDevice { [SaveState.DoNotSave] private readonly int[][] _banksA; //8000 [SaveState.DoNotSave] private readonly int[][] _banksB = new int[0][]; //A000 [SaveState.SaveWithName("BankMask")] private readonly int _bankMask; [SaveState.SaveWithName("BankNumber")] private int _bankNumber; [SaveState.DoNotSave] private int[] _currentBankA; [SaveState.DoNotSave] private int[] _currentBankB; [SaveState.DoNotSave] private readonly int[] _dummyBank; public Mapper0005(IList newAddresses, IList newBanks, IList newData) { var count = newAddresses.Count; // build dummy bank _dummyBank = new int[0x2000]; for (var i = 0; i < 0x2000; i++) _dummyBank[i] = 0xFF; // todo: determine if this is correct switch (count) { case 64: pinGame = true; pinExRom = false; _bankMask = 0x3F; _banksA = new int[64][]; break; case 32: // this specific config is a weird exception pinGame = false; pinExRom = false; _bankMask = 0x0F; _banksA = new int[16][]; _banksB = new int[16][]; break; case 16: pinGame = true; pinExRom = false; _bankMask = 0x0F; _banksA = new int[16][]; break; case 8: pinGame = true; pinExRom = false; _bankMask = 0x07; _banksA = new int[8][]; break; case 4: pinGame = true; pinExRom = false; _bankMask = 0x03; _banksA = new int[4][]; break; case 2: pinGame = true; pinExRom = false; _bankMask = 0x01; _banksA = new int[2][]; break; case 1: pinGame = true; pinExRom = false; _bankMask = 0x00; _banksA = new int[1][]; break; default: throw new Exception("This looks like an Ocean cartridge but cannot be loaded..."); } // for safety, initialize all banks to dummy for (var i = 0; i < _banksA.Length; i++) _banksA[i] = _dummyBank; for (var i = 0; i < _banksB.Length; i++) _banksB[i] = _dummyBank; // now load in the banks for (var i = 0; i < count; i++) { switch (newAddresses[i]) { case 0x8000: _banksA[newBanks[i] & _bankMask] = newData[i]; break; case 0xA000: case 0xE000: _banksB[newBanks[i] & _bankMask] = newData[i]; break; } } BankSet(0); } private void BankSet(int index) { _bankNumber = index & _bankMask; _currentBankA = !pinExRom ? _banksA[_bankNumber] : _dummyBank; _currentBankB = !pinGame ? _banksB[_bankNumber] : _dummyBank; } public override int Peek8000(int addr) { return _currentBankA[addr]; } public override int PeekA000(int addr) { return _currentBankB[addr]; } public override void PokeDE00(int addr, int val) { if (addr == 0x00) BankSet(val); } public override int Read8000(int addr) { return _currentBankA[addr]; } public override int ReadA000(int addr) { return _currentBankB[addr]; } public override void WriteDE00(int addr, int val) { if (addr == 0x00) BankSet(val); } public override void SyncState(Serializer ser) { base.SyncState(ser); if (ser.IsReader) BankSet(_bankNumber); } } } }