BizHawk/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/Tia.PlayerData.cs

194 lines
4.8 KiB
C#
Raw Normal View History

using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
public partial class TIA
{
private struct PlayerData
{
public MissileData Missile;
public byte Grp;
public byte Dgrp;
public byte Color;
public byte HPosCnt;
public byte ScanCnt;
public bool ScanCntInit;
public byte HM;
public bool Reflect;
public bool Delay;
public byte Nusiz;
public byte Collisions;
2016-05-17 00:35:52 +00:00
// Resp commands do not trigger start signals for main copies. We need to model this
public int Start_Signal;
public int Signal_Reached;
2016-05-16 00:43:21 +00:00
public bool Tick()
{
var result = false;
if (ScanCnt < 8)
{
if (!ScanCntInit)
{
// Make the mask to check the graphic
byte playerMask = (byte)(1 << (8 - 1 - ScanCnt));
// Reflect it if needed
if (Reflect)
{
playerMask = (byte)ReverseBits(playerMask, 8);
}
// Check the graphic (depending on delay)
if (!Delay)
{
if ((Grp & playerMask) != 0)
{
result = true;
}
}
else
{
if ((Dgrp & playerMask) != 0)
{
result = true;
}
}
// Reset missile, if desired
if (ScanCnt == 0x04 && HPosCnt <= 16 && Missile.ResetToPlayer)
{
Missile.HPosCnt = 0;
}
}
// Increment the Player Graphics Scan Counter
// This counter advances once per clock for single sized players,
// once every 2 clocks for double sized players (Nusiz == 0x05),
// and once every 4 clocks for quad sizes players (Nusize == 0x07)
// The ticks for starting and advancing this counter are tied to the div4 clocking phase.
// The first tick for single sized players happens immediately.
// The first tick for double and quad sized players is delayed one clock cycle,
// and then happen every 2 or 4 clocks
if ((Nusiz & 0x07) == 0x05)
{
if ((HPosCnt + 3) % 2 == 0)
{
if (ScanCntInit)
{
ScanCntInit = false;
ScanCnt = 0;
}
else
{
ScanCnt++;
}
}
}
else if ((Nusiz & 0x07) == 0x07)
{
if ((HPosCnt + 3) % 4 == 0)
{
if (ScanCntInit)
{
ScanCntInit = false;
ScanCnt = 0;
}
else
{
ScanCnt++;
}
}
}
else
{
ScanCntInit = false;
ScanCnt++;
}
}
// At counter position 0 we should initalize the scan counter.
// Note that for double and quad sized players that the scan counter is not started immediately.
2016-05-17 00:35:52 +00:00
if (Start_Signal==160)
2016-05-16 00:43:21 +00:00
{
ScanCnt = 0;
2016-05-17 00:35:52 +00:00
Start_Signal++;
if ((Nusiz & 0x07) == 0x05)
{
ScanCntInit = true;
}
else if ((Nusiz & 0x07) == 0x07)
{
ScanCntInit = true;
}
else
{
ScanCntInit = false;
}
}
2016-05-17 00:35:52 +00:00
if (Start_Signal == 16 && ((Nusiz & 0x07) == 0x01 || ((Nusiz & 0x07) == 0x03)))
{
ScanCnt = 0;
2016-05-17 00:35:52 +00:00
Start_Signal++;
}
2016-05-17 00:35:52 +00:00
if (Start_Signal == 32 && ((Nusiz & 0x07) == 0x02 || ((Nusiz & 0x07) == 0x03) || ((Nusiz & 0x07) == 0x06)))
{
ScanCnt = 0;
2016-05-17 00:35:52 +00:00
Start_Signal++;
}
2016-05-17 00:35:52 +00:00
if (Start_Signal == 64 && ((Nusiz & 0x07) == 0x04 || ((Nusiz & 0x07) == 0x06)))
{
ScanCnt = 0;
2016-05-17 00:35:52 +00:00
Start_Signal++;
}
// Increment the counter
HPosCnt++;
// Counter loops at 160
HPosCnt %= 160;
2016-05-17 00:35:52 +00:00
//our goal here is to send a start signal 4 clocks before drawing begins. This properly emulates
//drawing on a real TIA
if (HPosCnt==156 || HPosCnt==12 || HPosCnt==28 || HPosCnt==60)
{
Start_Signal = HPosCnt-1;
Signal_Reached = HPosCnt + 5;
}
if (Start_Signal<Signal_Reached)
{
Start_Signal++;
}
return result;
}
public void SyncState(Serializer ser)
{
Missile.SyncState(ser);
ser.Sync("grp", ref Grp);
ser.Sync("dgrp", ref Dgrp);
ser.Sync("color", ref Color);
ser.Sync("hPosCnt", ref HPosCnt);
ser.Sync("scanCnt", ref ScanCnt);
ser.Sync("scanCntInit", ref ScanCntInit);
ser.Sync("HM", ref HM);
ser.Sync("reflect", ref Reflect);
ser.Sync("delay", ref Delay);
ser.Sync("nusiz", ref Nusiz);
ser.Sync("collisions", ref Collisions);
2016-05-17 00:35:52 +00:00
ser.Sync("start_signal", ref Start_Signal);
ser.Sync("signal_reached", ref Signal_Reached);
2016-05-16 00:43:21 +00:00
}
}
}
}