mirror of https://github.com/Washi1337/Emux.git
109 lines
3.6 KiB
C#
109 lines
3.6 KiB
C#
using System;
|
|
|
|
namespace Emux.GameBoy.Cartridge
|
|
{
|
|
public class MemoryBankController3 : IMemoryBankController
|
|
{
|
|
private readonly IFullyAccessibleCartridge _cartridge;
|
|
private readonly byte[] _romBank = new byte[0x4000];
|
|
private int _romBankIndex = 0;
|
|
private int _ramBankOrRtcIndex;
|
|
private readonly byte[] _rtc = new byte[5];
|
|
|
|
public MemoryBankController3(IFullyAccessibleCartridge cartridge)
|
|
{
|
|
if (cartridge == null)
|
|
throw new ArgumentNullException(nameof(cartridge));
|
|
_cartridge = cartridge;
|
|
}
|
|
|
|
public void Initialize()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
SwitchRomBank(1);
|
|
}
|
|
|
|
public void Shutdown()
|
|
{
|
|
}
|
|
|
|
public byte ReadByte(ushort address)
|
|
{
|
|
if (address < 0x4000)
|
|
return _cartridge.ReadFromAbsoluteAddress(address);
|
|
if (address < 0x8000)
|
|
return _romBank[address - 0x4000];
|
|
if (_cartridge.ExternalMemory.IsActive && address >= 0xA000 && address < 0xC000)
|
|
return ReadRamOrRtc(address);
|
|
return 0;
|
|
}
|
|
|
|
private byte ReadRamOrRtc(ushort address)
|
|
{
|
|
return _ramBankOrRtcIndex <= 3
|
|
? (_cartridge.CartridgeType.HasRam()
|
|
? _cartridge.ExternalMemory.ReadByte(address - 0xA000 + GetRamOffset())
|
|
: (byte) 0)
|
|
: (_cartridge.CartridgeType.HasTimer()
|
|
? _rtc[_ramBankOrRtcIndex - 0x8]
|
|
: (byte) 0);
|
|
}
|
|
|
|
public void ReadBytes(ushort address, byte[] buffer, int bufferOffset, int length)
|
|
{
|
|
if (address < 0x4000)
|
|
_cartridge.ReadFromAbsoluteAddress(address, buffer, bufferOffset, length);
|
|
else if (address < 0x8000)
|
|
Buffer.BlockCopy(_romBank, address - 0x4000, buffer, bufferOffset, length);
|
|
if (_cartridge.ExternalMemory.IsActive && address >= 0xA000 && address <= 0xBFFF)
|
|
_cartridge.ExternalMemory.ReadBytes(address - 0xA000 + GetRamOffset(), buffer, bufferOffset, length);
|
|
}
|
|
|
|
public void WriteByte(ushort address, byte value)
|
|
{
|
|
if (address < 0x2000)
|
|
{
|
|
if ((value & 0xA) == 0xA)
|
|
_cartridge.ExternalMemory.Activate();
|
|
else
|
|
_cartridge.ExternalMemory.Deactivate();
|
|
}
|
|
else if (address < 0x4000)
|
|
SwitchRomBank(value & 0x7F);
|
|
else if (address < 0x6000)
|
|
_ramBankOrRtcIndex = value & 3;
|
|
else if (address < 0x8000)
|
|
{
|
|
// TODO: latch clock data
|
|
}
|
|
else if (_cartridge.ExternalMemory.IsActive && address >= 0xA000 && address - 0xA000 < _cartridge.ExternalRamSize)
|
|
_cartridge.ExternalMemory.WriteByte(address - 0xA000 + GetRamOffset(), value);
|
|
}
|
|
|
|
private void SwitchRomBank(int index)
|
|
{
|
|
if (_romBankIndex != index)
|
|
{
|
|
if (index == 0)
|
|
index++;
|
|
_romBankIndex = index & 0x7F;
|
|
UpdateRomBank();
|
|
}
|
|
}
|
|
|
|
private void UpdateRomBank()
|
|
{
|
|
_cartridge.ReadFromAbsoluteAddress(_romBank.Length * _romBankIndex, _romBank, 0, _romBank.Length);
|
|
}
|
|
|
|
private int GetRamOffset()
|
|
{
|
|
return _ramBankOrRtcIndex * 0x2000;
|
|
}
|
|
|
|
}
|
|
} |