176 lines
3.8 KiB
C#
176 lines
3.8 KiB
C#
using BizHawk.Common.NumberExtensions;
|
|
using BizHawk.Common;
|
|
|
|
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
|
|
{
|
|
public class SerialPort
|
|
{
|
|
public GBHawk Core { get; set; }
|
|
|
|
public byte serial_control;
|
|
public byte serial_data;
|
|
public bool serial_start;
|
|
public bool can_pulse;
|
|
public int serial_clock;
|
|
public int serial_bits;
|
|
public int clk_rate;
|
|
public byte going_out;
|
|
public byte coming_in;
|
|
|
|
public byte ReadReg(int addr)
|
|
{
|
|
switch (addr)
|
|
{
|
|
case 0xFF01:
|
|
return serial_data;
|
|
case 0xFF02:
|
|
return serial_control;
|
|
}
|
|
|
|
return 0xFF;
|
|
}
|
|
|
|
public void WriteReg(int addr, byte value)
|
|
{
|
|
switch (addr)
|
|
{
|
|
case 0xFF01:
|
|
serial_data = value;
|
|
break;
|
|
|
|
case 0xFF02:
|
|
if (((value & 0x80) > 0) && !serial_start)
|
|
{
|
|
serial_start = true;
|
|
serial_bits = 8;
|
|
if ((value & 1) > 0)
|
|
{
|
|
if (((value & 2) > 0) && Core.GBC_compat)
|
|
{
|
|
clk_rate = 16;
|
|
serial_clock = (16 - (int)(Core.cpu.TotalExecutedCycles % 8)) + 1;
|
|
}
|
|
else
|
|
{
|
|
clk_rate = 512;
|
|
serial_clock = 512 - (int)(Core.cpu.TotalExecutedCycles % 256) + 1;
|
|
|
|
// there seems to be some clock inverting happening on some transfers
|
|
// not sure of the exact nature of it, here is one methor that gives correct result on one test rom but not others
|
|
/*
|
|
if (Core._syncSettings.GBACGB && Core.is_GBC)
|
|
{
|
|
if ((Core.TotalExecutedCycles % 256) > 127)
|
|
{
|
|
serial_clock = (8 - (int)(Core.cpu.TotalExecutedCycles % 8)) + 1;
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
can_pulse = true;
|
|
}
|
|
else
|
|
{
|
|
clk_rate = -1;
|
|
serial_clock = clk_rate;
|
|
can_pulse = false;
|
|
}
|
|
}
|
|
else if (serial_start)
|
|
{
|
|
if ((value & 1) > 0)
|
|
{
|
|
if (((value & 2) > 0) && Core.GBC_compat)
|
|
{
|
|
clk_rate = 16;
|
|
serial_clock = (16 - (int)(Core.cpu.TotalExecutedCycles % 8)) + 1;
|
|
}
|
|
else
|
|
{
|
|
clk_rate = 512;
|
|
serial_clock = 512 - (int)(Core.cpu.TotalExecutedCycles % 256) + 1;
|
|
}
|
|
can_pulse = true;
|
|
}
|
|
else
|
|
{
|
|
clk_rate = -1;
|
|
serial_clock = clk_rate;
|
|
can_pulse = false;
|
|
}
|
|
}
|
|
|
|
if (Core.GBC_compat)
|
|
{
|
|
serial_control = (byte)(0x7C | (value & 0x83)); // extra CGB bit
|
|
}
|
|
else
|
|
{
|
|
serial_control = (byte)(0x7E | (value & 0x81)); // middle six bits always 1
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
public void serial_transfer_tick()
|
|
{
|
|
if (serial_start)
|
|
{
|
|
if (serial_clock > 0) { serial_clock--; }
|
|
|
|
if (serial_clock == 0)
|
|
{
|
|
if (serial_bits > 0)
|
|
{
|
|
serial_data = (byte)((serial_data << 1) | coming_in);
|
|
|
|
serial_bits--;
|
|
|
|
if (serial_bits == 0)
|
|
{
|
|
serial_control &= 0x7F;
|
|
serial_start = false;
|
|
|
|
if (Core.REG_FFFF.Bit(3)) { Core.cpu.FlagI = true; }
|
|
Core.REG_FF0F |= 0x08;
|
|
}
|
|
else
|
|
{
|
|
serial_clock = clk_rate;
|
|
if (clk_rate > 0) { can_pulse = true; }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
serial_control = 0x7E;
|
|
serial_data = 0x00;
|
|
serial_start = false;
|
|
serial_clock = 0;
|
|
serial_bits = 0;
|
|
clk_rate = 16;
|
|
going_out = 0;
|
|
coming_in = 1;
|
|
can_pulse = false;
|
|
}
|
|
|
|
public void SyncState(Serializer ser)
|
|
{
|
|
ser.Sync(nameof(serial_control), ref serial_control);
|
|
ser.Sync(nameof(serial_data), ref serial_data);
|
|
ser.Sync(nameof(serial_start), ref serial_start);
|
|
ser.Sync(nameof(serial_clock), ref serial_clock);
|
|
ser.Sync(nameof(serial_bits), ref serial_bits);
|
|
ser.Sync(nameof(clk_rate), ref clk_rate);
|
|
ser.Sync(nameof(going_out), ref going_out);
|
|
ser.Sync(nameof(coming_in), ref coming_in);
|
|
ser.Sync(nameof(can_pulse), ref can_pulse);
|
|
}
|
|
}
|
|
}
|