GBA.Unity/Assets/Iris/Iris.GBA/Communication.cs
2024-08-15 13:19:43 +08:00

251 lines
7.3 KiB
C#

using System;
using System.IO;
namespace Iris.GBA
{
internal sealed class Communication
{
internal enum Register
{
SIODATA0,
SIODATA1,
SIODATA2,
SIODATA3,
SIOCNT,
SIODATA_SEND,
RCNT,
JOYCNT,
JOY_RECV_L,
JOY_RECV_H,
JOY_TRANS_L,
JOY_TRANS_H,
JOYSTAT
}
private UInt16 _SIODATA0; // SIOMULTI0 / SIODATA32_L
private UInt16 _SIODATA1; // SIOMULTI1 / SIODATA32_H
private UInt16 _SIODATA2; // SIOMULTI2
private UInt16 _SIODATA3; // SIOMULTI3
private UInt16 _SIOCNT;
private UInt16 _SIODATA_SEND; // SIOMLT_SEND / SIODATA_8
private UInt16 _RCNT;
private UInt16 _JOYCNT;
private UInt16 _JOY_RECV_L;
private UInt16 _JOY_RECV_H;
private UInt16 _JOY_TRANS_L;
private UInt16 _JOY_TRANS_H;
private UInt16 _JOYSTAT;
private InterruptControl _interruptControl;
internal void Initialize(InterruptControl interruptControl)
{
_interruptControl = interruptControl;
}
internal void ResetState()
{
_SIODATA0 = 0;
_SIODATA1 = 0;
_SIODATA2 = 0;
_SIODATA3 = 0;
_SIOCNT = 0;
_SIODATA_SEND = 0;
_RCNT = 0;
_JOYCNT = 0;
_JOY_RECV_L = 0;
_JOY_RECV_H = 0;
_JOY_TRANS_L = 0;
_JOY_TRANS_H = 0;
_JOYSTAT = 0;
}
internal void LoadState(BinaryReader reader)
{
_SIODATA0 = reader.ReadUInt16();
_SIODATA1 = reader.ReadUInt16();
_SIODATA2 = reader.ReadUInt16();
_SIODATA3 = reader.ReadUInt16();
_SIOCNT = reader.ReadUInt16();
_SIODATA_SEND = reader.ReadUInt16();
_RCNT = reader.ReadUInt16();
_JOYCNT = reader.ReadUInt16();
_JOY_RECV_L = reader.ReadUInt16();
_JOY_RECV_H = reader.ReadUInt16();
_JOY_TRANS_L = reader.ReadUInt16();
_JOY_TRANS_H = reader.ReadUInt16();
_JOYSTAT = reader.ReadUInt16();
}
internal void SaveState(BinaryWriter writer)
{
writer.Write(_SIODATA0);
writer.Write(_SIODATA1);
writer.Write(_SIODATA2);
writer.Write(_SIODATA3);
writer.Write(_SIOCNT);
writer.Write(_SIODATA_SEND);
writer.Write(_RCNT);
writer.Write(_JOYCNT);
writer.Write(_JOY_RECV_L);
writer.Write(_JOY_RECV_H);
writer.Write(_JOY_TRANS_L);
writer.Write(_JOY_TRANS_H);
writer.Write(_JOYSTAT);
}
internal UInt16 ReadRegister(Register register)
{
return register switch
{
Register.SIODATA0 => _SIODATA0,
Register.SIODATA1 => _SIODATA1,
Register.SIODATA2 => _SIODATA2,
Register.SIODATA3 => _SIODATA3,
Register.SIOCNT => _SIOCNT,
Register.SIODATA_SEND => _SIODATA_SEND,
Register.RCNT => _RCNT,
Register.JOYCNT => _JOYCNT,
Register.JOY_RECV_L => _JOY_RECV_L,
Register.JOY_RECV_H => _JOY_RECV_H,
Register.JOY_TRANS_L => _JOY_TRANS_L,
Register.JOY_TRANS_H => _JOY_TRANS_H,
Register.JOYSTAT => _JOYSTAT,
// should never happen
_ => throw new Exception("Iris.GBA.Communication: Register read error"),
};
}
internal void WriteRegister(Register register, UInt16 value, Memory.RegisterWriteMode mode)
{
switch (register)
{
case Register.SIODATA0:
Memory.WriteRegisterHelper(ref _SIODATA0, value, mode);
break;
case Register.SIODATA1:
Memory.WriteRegisterHelper(ref _SIODATA1, value, mode);
break;
case Register.SIODATA2:
Memory.WriteRegisterHelper(ref _SIODATA2, value, mode);
break;
case Register.SIODATA3:
Memory.WriteRegisterHelper(ref _SIODATA3, value, mode);
break;
case Register.SIOCNT:
Memory.WriteRegisterHelper(ref _SIOCNT, value, mode);
CheckTransfer();
break;
case Register.SIODATA_SEND:
Memory.WriteRegisterHelper(ref _SIODATA_SEND, value, mode);
break;
case Register.RCNT:
Memory.WriteRegisterHelper(ref _RCNT, value, mode);
CheckTransfer();
break;
case Register.JOYCNT:
Memory.WriteRegisterHelper(ref _JOYCNT, value, mode);
break;
case Register.JOY_RECV_L:
Memory.WriteRegisterHelper(ref _JOY_RECV_L, value, mode);
break;
case Register.JOY_RECV_H:
Memory.WriteRegisterHelper(ref _JOY_RECV_H, value, mode);
break;
case Register.JOY_TRANS_L:
Memory.WriteRegisterHelper(ref _JOY_TRANS_L, value, mode);
break;
case Register.JOY_TRANS_H:
Memory.WriteRegisterHelper(ref _JOY_TRANS_H, value, mode);
break;
case Register.JOYSTAT:
Memory.WriteRegisterHelper(ref _JOYSTAT, value, mode);
break;
// should never happen
default:
throw new Exception("Iris.GBA.Communication: Register write error");
}
}
private void CheckTransfer()
{
switch ((_RCNT >> 14) & 0b11)
{
case 0b00:
case 0b01:
switch ((_SIOCNT >> 12) & 0b11)
{
case 0b00: // 8 bits normal serial communication
case 0b01: // 32 bits normal serial communication
case 0b10: // 16 bits multiplayer serial communication
if ((_SIOCNT & 0x0080) == 0x0080)
{
_SIOCNT = (UInt16)(_SIOCNT & ~0x0080);
if ((_SIOCNT & 0x4000) == 0x4000)
_interruptControl.RequestInterrupt(InterruptControl.Interrupt.SIO);
}
break;
case 0b11:
Console.WriteLine("[Iris.GBA.Communication] UART communication not implemented");
break;
}
break;
case 0b10:
Console.WriteLine("[Iris.GBA.Communication] General purpose communication not implemented");
break;
case 0b11:
Console.WriteLine("[Iris.GBA.Communication] JOY Bus communication not implemented");
break;
}
}
}
}