Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/BizHawk.Emulation.Cores/Computers/Commodore64/Cartridge/Mapper0005.cs
2 views
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<int> newAddresses, IList<int> newBanks, IList<int[]> 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);
            }
        }
    }
}