193 lines
4.5 KiB
C#
193 lines
4.5 KiB
C#
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;
|
|
|
|
// Resp commands do not trigger start signals for main copies. We need to model this
|
|
private int _startSignal;
|
|
private int _signalReached;
|
|
|
|
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.
|
|
if (_startSignal == 160)
|
|
{
|
|
ScanCnt = 0;
|
|
_startSignal++;
|
|
if ((Nusiz & 0x07) == 0x05)
|
|
{
|
|
ScanCntInit = true;
|
|
}
|
|
else if ((Nusiz & 0x07) == 0x07)
|
|
{
|
|
ScanCntInit = true;
|
|
}
|
|
else
|
|
{
|
|
ScanCntInit = false;
|
|
}
|
|
}
|
|
|
|
if (_startSignal == 16 && ((Nusiz & 0x07) == 0x01 || ((Nusiz & 0x07) == 0x03)))
|
|
{
|
|
ScanCnt = 0;
|
|
_startSignal++;
|
|
}
|
|
|
|
if (_startSignal == 32 && ((Nusiz & 0x07) == 0x02 || ((Nusiz & 0x07) == 0x03) || ((Nusiz & 0x07) == 0x06)))
|
|
{
|
|
ScanCnt = 0;
|
|
_startSignal++;
|
|
}
|
|
|
|
if (_startSignal == 64 && ((Nusiz & 0x07) == 0x04 || ((Nusiz & 0x07) == 0x06)))
|
|
{
|
|
ScanCnt = 0;
|
|
_startSignal++;
|
|
}
|
|
|
|
// Increment the counter
|
|
HPosCnt++;
|
|
|
|
// Counter loops at 160
|
|
HPosCnt %= 160;
|
|
|
|
// 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)
|
|
{
|
|
_startSignal = HPosCnt - 1;
|
|
_signalReached = HPosCnt + 5;
|
|
}
|
|
|
|
if (_startSignal < _signalReached)
|
|
{
|
|
_startSignal++;
|
|
}
|
|
|
|
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);
|
|
ser.Sync("start_signal", ref _startSignal);
|
|
ser.Sync("signal_reached", ref _signalReached);
|
|
}
|
|
}
|
|
}
|
|
}
|