forked from sin365/AxibugEmuOnline
166 lines
5.1 KiB
C#
166 lines
5.1 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|