AxibugEmuOnline/AxibugEmuOnline.Client/Assets/Runtime/Core/CPU.Memory.cs

166 lines
5.1 KiB
C#
Raw Normal View History

2024-06-28 18:08:25 +08:00
using System;
using System.Linq;
using System.Runtime.CompilerServices;
using static AxibugEmuOnline.Client.UNES.CPU.AddressingMode;
namespace AxibugEmuOnline.Client.UNES
{
sealed partial class CPU
{
public enum AddressingMode
{
None,
Direct,
Immediate,
ZeroPage,
Absolute,
ZeroPageX,
ZeroPageY,
AbsoluteX,
AbsoluteY,
IndirectX,
IndirectY
}
private uint? _currentMemoryAddress;
private uint _rmwValue;
private void ResetInstructionAddressingMode() => _currentMemoryAddress = null;
private uint _Address()
{
var def = _opCodeDefs[_currentInstruction];
switch (def.Mode)
{
case Immediate:
return PC++;
case ZeroPage:
return NextByte();
case Absolute:
return NextWord();
case ZeroPageX:
return (NextByte() + X) & 0xFF;
case ZeroPageY:
return (NextByte() + Y) & 0xFF;
case AbsoluteX:
var address = NextWord();
if (def.PageBoundary && (address & 0xFF00) != ((address + X) & 0xFF00))
{
Cycle += 1;
}
return address + X;
case AbsoluteY:
address = NextWord();
if (def.PageBoundary && (address & 0xFF00) != ((address + Y) & 0xFF00))
{
Cycle += 1;
}
return address + Y;
case IndirectX:
var off = (NextByte() + X) & 0xFF;
return ReadByte(off) | (ReadByte((off + 1) & 0xFF) << 8);
case IndirectY:
off = NextByte() & 0xFF;
address = ReadByte(off) | (ReadByte((off + 1) & 0xFF) << 8);
if (def.PageBoundary && (address & 0xFF00) != ((address + Y) & 0xFF00))
{
Cycle += 1;
}
return (address + Y) & 0xFFFF;
}
throw new NotImplementedException();
}
public uint AddressRead()
{
if (_opCodeDefs[_currentInstruction].Mode == Direct)
{
return _rmwValue = A;
}
if (_currentMemoryAddress == null)
{
_currentMemoryAddress = _Address();
}
return _rmwValue = ReadByte((uint)_currentMemoryAddress) & 0xFF;
}
public void AddressWrite(uint val)
{
if (_opCodeDefs[_currentInstruction].Mode == Direct)
{
A = val;
}
else
{
if (_currentMemoryAddress == null)
{
_currentMemoryAddress = _Address();
}
if (_opCodeDefs[_currentInstruction].RMW)
{
WriteByte((uint)_currentMemoryAddress, _rmwValue);
}
WriteByte((uint)_currentMemoryAddress, val);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private uint ReadWord(uint address) => ReadByte(address) | (ReadByte(address + 1) << 8);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private uint NextByte() => ReadByte(PC++);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private uint NextWord() => NextByte() | (NextByte() << 8);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private sbyte NextSByte() => (sbyte)NextByte();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Push(uint what)
{
WriteByte(0x100 + SP, what);
SP--;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private uint Pop()
{
SP++;
return ReadByte(0x100 + SP);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void PushWord(uint what)
{
Push(what >> 8);
Push(what & 0xFF);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private uint PopWord() => Pop() | (Pop() << 8);
protected override void InitializeMemoryMap()
{
base.InitializeMemoryMap();
MapReadHandler(0x0000, 0x1FFF, address => _ram[address & 0x07FF]);
MapReadHandler(0x2000, 0x3FFF, address => _emulator.PPU.ReadRegister((address & 0x7) - 0x2000));
MapReadHandler(0x4000, 0x4017, ReadIORegister);
MapWriteHandler(0x0000, 0x1FFF, (address, val) => _ram[address & 0x07FF] = val);
MapWriteHandler(0x2000, 0x3FFF, (address, val) => _emulator.PPU.WriteRegister((address & 0x7) - 0x2000, val));
MapWriteHandler(0x4000, 0x401F, WriteIoRegister);
_emulator.Mapper.InitializeMemoryMap(this);
}
}
}