Merge pull request #614 from alyosha-tas/master

AtariHawk bug fixes pull request
This commit is contained in:
hegyak 2016-04-18 08:06:15 -07:00
commit 643e475ccc
3 changed files with 2252 additions and 411 deletions

View File

@ -268,6 +268,39 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
private int[] _palette;
private int test_count_p0;
private int test_count_p1;
private int test_count_m0;
private int test_count_m1;
private int test_count_b;
private byte pf0_update = 0;
private byte pf1_update = 0;
private byte pf2_update = 0;
private bool pf0_updater = false;
private bool pf1_updater = false;
private bool pf2_updater = false;
private byte pf0_delay_clock = 0;
private byte pf1_delay_clock = 0;
private byte pf2_delay_clock = 0;
private byte pf0_max_delay = 0;
private byte pf1_max_delay = 0;
private byte pf2_max_delay = 0;
private int enam0_delay = 0;
private int enam1_delay = 0;
private int enamb_delay = 0;
private bool enam0_val = false;
private bool enam1_val = false;
private bool enamb_val = false;
private int prg0_delay = 0;
private int prg1_delay = 0;
private byte prg0_val = 0;
private byte prg1_val = 0;
private bool do_ticks = false;
private byte _hsyncCnt;
private int _capChargeStart;
private bool _capCharging;
@ -395,6 +428,98 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
{
// Still ignoring cycles...
//delay latch to new playfield register
if (pf0_updater==true)
{
pf0_delay_clock++;
if (pf0_delay_clock > pf0_max_delay)
{
_playField.Grp = (uint)((_playField.Grp & 0x0FFFF) + ((ReverseBits(pf0_update, 8) & 0x0F) << 16));
pf0_updater = false;
}
}
if (pf1_updater == true)
{
pf1_delay_clock++;
if (pf1_delay_clock > pf1_max_delay)
{
_playField.Grp = (uint)((_playField.Grp & 0xF00FF) + (pf1_update << 8));
pf1_updater = false;
}
}
if (pf2_updater == true)
{
pf2_delay_clock++;
if (pf2_delay_clock > pf2_max_delay)
{
_playField.Grp = (uint)((_playField.Grp & 0xFFF00) + ReverseBits(pf2_update, 8));
pf2_updater = false;
}
}
//delay latch to missile enable
if (enam0_delay>0)
{
enam0_delay++;
if (enam0_delay==3)
{
enam0_delay = 0;
_player0.Missile.Enabled = enam0_val;
}
}
if (enam1_delay > 0)
{
enam1_delay++;
if (enam1_delay == 3)
{
enam1_delay = 0;
_player1.Missile.Enabled = enam1_val;
}
}
// delay latch to ball enable
if (enamb_delay > 0)
{
enamb_delay++;
if (enamb_delay == 3)
{
enamb_delay = 0;
_ball.Enabled = enamb_val;
}
}
// delay latch to player graphics registers
if (prg0_delay > 0)
{
prg0_delay++;
if (prg0_delay == 3)
{
prg0_delay = 0;
_player0.Grp = prg0_val;
_player1.Dgrp = _player1.Grp;
}
}
if (prg1_delay > 0)
{
prg1_delay++;
if (prg1_delay == 3)
{
prg1_delay = 0;
_player1.Grp = prg1_val;
_player0.Dgrp = _player0.Grp;
// TODO: Find a game that uses this functionality and test it
_ball.Denabled = _ball.Enabled;
}
}
// Reset the RDY flag when we reach hblank
if (_hsyncCnt <= 0)
{
@ -406,8 +531,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// ---- Things that happen only in the drawing section ----
// TODO: Remove this magic number (17). It depends on the HMOVE
if ((_hsyncCnt / 4) >= (_hmove.LateHBlankReset ? 19 : 17))
if ((_hsyncCnt) >= (_hmove.LateHBlankReset ? 76 : 68))
{
do_ticks = false;
// TODO: Remove this magic number
if ((_hsyncCnt / 4) >= 37)
{
@ -523,16 +650,16 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
}
if (_playField.Priority && (collisions & CXPF) != 0 && _core.Settings.ShowPlayfield)
{
if (_playField.Score)
if (_playField.Score && !_playField.Priority && (collisions & CXPF) != 0 && _core.Settings.ShowPlayfield)
{
pixelColor = !rightSide ? _palette[_player0.Color] : _palette[_player1.Color];
}
else
if (_playField.Priority && (collisions & CXPF) != 0 && _core.Settings.ShowPlayfield)
{
pixelColor = _palette[_playField.PfColor];
}
}
// Handle vblank
@ -554,8 +681,33 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
throw new Exception(); // TODO
_scanlinebuffer[_CurrentScanLine * ScreenWidth + x] = pixelColor;
}
} else
{
do_ticks = true;
}
// if extended HBLank is active, the screen area still needs a color
if (_hsyncCnt >= 68 && _hsyncCnt < 76 && _hmove.LateHBlankReset)
{
int pixelColor = 0;
// Add the pixel to the scanline
// TODO: Remove this magic number (68)
int y = _CurrentScanLine;
// y >= max screen height means lag frame or game crashed, but is a legal situation.
// either way, there's nothing to display
if (y < MaxScreenHeight)
{
int x = _hsyncCnt - 68;
if (x < 0 || x > 159) // this can't happen, right?
throw new Exception(); // TODO
_scanlinebuffer[_CurrentScanLine * ScreenWidth + x] = pixelColor;
}
}
// ---- Things that happen every time ----
// Handle HMOVE
@ -564,8 +716,16 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// On the first time, set the latches and counters
if (_hmove.HMoveJustStarted)
{
_hmove.Player0Latch = true;
_hmove.Player0Cnt = 0;
test_count_p0 = 0;
test_count_p1 = 0;
test_count_m0 = 0;
test_count_m1 = 0;
test_count_b = 0;
_hmove.Missile0Latch = true;
_hmove.Missile0Cnt = 0;
@ -584,10 +744,13 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
_hmove.HMoveJustStarted = false;
_hmove.LateHBlankReset = true;
_hmove.DecCntEnabled = false;
}
if (_hmove.DecCntEnabled)
{
// Actually do stuff only evey 4 pulses
if (_hmove.HMoveCnt == 0)
{
@ -598,11 +761,25 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if (((15 - _hmove.Player0Cnt) ^ ((_player0.HM & 0x07) | ((~(_player0.HM & 0x08)) & 0x08))) != 0x0F)
{
// "Clock-Stuffing"
if (do_ticks==true)
{
_player0.Tick();
}
// Increase by 1, max of 15
test_count_p0++;
if (test_count_p0 < 16)
{
_hmove.Player0Cnt++;
_hmove.Player0Cnt %= 16;
}
else
{
_hmove.Player0Cnt = 0;
}
//_hmove.Player0Cnt %= 16;
}
else
{
@ -612,23 +789,33 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if (_hmove.Missile0Latch)
{
if (_hmove.Missile0Cnt == 15)
{ }
// If the move counter still has a bit in common with the HM register
if (((15 - _hmove.Missile0Cnt) ^ ((_player0.Missile.Hm & 0x07) | ((~(_player0.Missile.Hm & 0x08)) & 0x08))) != 0x0F)
{
// "Clock-Stuffing"
if (do_ticks == true)
{
_player0.Missile.Tick();
}
// Increase by 1, max of 15
test_count_m0++;
if (test_count_m0 < 16)
{
_hmove.Missile0Cnt++;
_hmove.Missile0Cnt %= 16;
}
else
{
_hmove.Missile0Cnt = 0;
}
//_hmove.Missile0Cnt %= 16;
}
else
{
_hmove.Missile0Latch = false;
_hmove.Missile0Cnt = 0;
}
}
@ -638,11 +825,21 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if (((15 - _hmove.Player1Cnt) ^ ((_player1.HM & 0x07) | ((~(_player1.HM & 0x08)) & 0x08))) != 0x0F)
{
// "Clock-Stuffing"
if (do_ticks == true)
{
_player1.Tick();
}
// Increase by 1, max of 15
test_count_p1++;
if (test_count_p1 < 16)
{
_hmove.Player1Cnt++;
_hmove.Player1Cnt %= 16;
}
else
{
_hmove.Player1Cnt = 0;
}
//_hmove.Player1Cnt %= 16;
}
else
{
@ -656,11 +853,21 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if (((15 - _hmove.Missile1Cnt) ^ ((_player1.Missile.Hm & 0x07) | ((~(_player1.Missile.Hm & 0x08)) & 0x08))) != 0x0F)
{
// "Clock-Stuffing"
if (do_ticks == true)
{
_player1.Missile.Tick();
}
// Increase by 1, max of 15
test_count_m1++;
if (test_count_m1 < 16)
{
_hmove.Missile1Cnt++;
_hmove.Missile1Cnt %= 16;
}
else
{
_hmove.Missile1Cnt = 0;
}
// _hmove.Missile1Cnt %= 16;
}
else
{
@ -674,11 +881,21 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
if (((15 - _hmove.BallCnt) ^ ((_ball.HM & 0x07) | ((~(_ball.HM & 0x08)) & 0x08))) != 0x0F)
{
// "Clock-Stuffing"
if (do_ticks == true)
{
_ball.Tick();
}
// Increase by 1, max of 15
test_count_b++;
if (test_count_b < 16)
{
_hmove.BallCnt++;
_hmove.BallCnt %= 16;
}
else
{
_hmove.BallCnt = 0;
}
//_hmove.BallCnt %= 16;
}
else
{
@ -698,12 +915,12 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
_hmove.HMoveCnt %= 4;
}
if (_hmove.HMoveDelayCnt < 6)
if (_hmove.HMoveDelayCnt < 5)
{
_hmove.HMoveDelayCnt++;
}
if (_hmove.HMoveDelayCnt == 6)
if (_hmove.HMoveDelayCnt == 5)
{
_hmove.HMoveDelayCnt++;
_hmove.HMoveCnt = 0;
@ -711,6 +928,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
}
// Increment the hsync counter
_hsyncCnt++;
_hsyncCnt %= 228;
@ -905,81 +1123,167 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
else if (maskedAddr == 0x0D) // PF0
{
_playField.Grp = (uint)((_playField.Grp & 0x0FFFF) + ((ReverseBits(value, 8) & 0x0F) << 16));
pf0_update = value;
pf0_updater = true;
pf0_delay_clock = 0;
if (((_hsyncCnt / 3) & 3) == 0)
{
pf0_max_delay = 4;
}
if (((_hsyncCnt / 3) & 3) == 1)
{
pf0_max_delay = 5;
}
if (((_hsyncCnt / 3) & 3) == 2)
{
pf0_max_delay = 2;
}
if (((_hsyncCnt / 3) & 3) == 3)
{
pf0_max_delay = 3;
}
//_playField.Grp = (uint)((_playField.Grp & 0x0FFFF) + ((ReverseBits(value, 8) & 0x0F) << 16));
}
else if (maskedAddr == 0x0E) // PF1
{
_playField.Grp = (uint)((_playField.Grp & 0xF00FF) + (value << 8));
pf1_update = value;
pf1_updater = true;
pf1_delay_clock = 0;
if (((_hsyncCnt / 3) & 3) == 0)
{
pf1_max_delay = 4;
}
if (((_hsyncCnt / 3) & 3) == 1)
{
pf1_max_delay = 5;
}
if (((_hsyncCnt / 3) & 3) == 2)
{
pf1_max_delay = 2;
}
if (((_hsyncCnt / 3) & 3) == 3)
{
pf1_max_delay = 3;
}
//_playField.Grp = (uint)((_playField.Grp & 0xF00FF) + (value << 8));
}
else if (maskedAddr == 0x0F) // PF2
{
_playField.Grp = (uint)((_playField.Grp & 0xFFF00) + ReverseBits(value, 8));
pf2_update = value;
pf2_updater = true;
pf2_delay_clock = 0;
if (((_hsyncCnt / 3) & 3) == 0)
{
pf2_max_delay = 4;
}
if (((_hsyncCnt / 3) & 3) == 1)
{
pf2_max_delay = 5;
}
if (((_hsyncCnt / 3) & 3) == 2)
{
pf2_max_delay = 2;
}
if (((_hsyncCnt / 3) & 3) == 3)
{
pf2_max_delay = 3;
}
//_playField.Grp = (uint)((_playField.Grp & 0xFFF00) + ReverseBits(value, 8));
}
else if (maskedAddr == 0x10) // RESP0
{
// Borrowed from EMU7800. Apparently resetting between 68 and 76 has strange results.
// Resp depends on HMOVE
if (!_hmove.LateHBlankReset)
{
if (_hsyncCnt < 69)
{
_player0.HPosCnt = 0;
_player0.ResetCnt = 0;
_player0.Reset = true;
}
else if (_hsyncCnt == 69)
{
_player0.ResetCnt = 3;
}
else if (_hsyncCnt == 72)
{
_player0.ResetCnt = 2;
}
else if (_hsyncCnt == 75)
{
_player0.ResetCnt = 1;
_player0.Reset = true;
}
else
{
_player0.ResetCnt = 0;
}
}
else
{
if (_hsyncCnt < 76)
{
_player0.HPosCnt = 0;
_player0.ResetCnt = 1;
_player0.Reset = true;
}
else
{
_player0.ResetCnt = 0;
}
}
}
else if (maskedAddr == 0x11) // RESP1
{
// Borrowed from EMU7800. Apparently resetting between 68 and 76 has strange results.
// This fixes some graphic glitches with Frostbite
// RESP depends on HMOVE
if (!_hmove.LateHBlankReset)
{
if (_hsyncCnt < 69)
{
_player1.HPosCnt = 0;
_player1.ResetCnt = 0;
_player1.Reset = true;
}
else if (_hsyncCnt == 69)
{
_player1.ResetCnt = 3;
}
else if (_hsyncCnt == 72)
{
_player1.ResetCnt = 2;
}
else if (_hsyncCnt == 75)
_player1.Reset = true;
} else
{
_player1.ResetCnt = 0;
}
} else
{
if (_hsyncCnt < 76)
{
_player1.HPosCnt = 0;
_player1.ResetCnt = 1;
_player1.Reset = true;
}
else
{
_player1.ResetCnt = 0;
}
}
}
else if (maskedAddr == 0x12) // RESM0
{
if (!_hmove.LateHBlankReset)
{
_player0.Missile.HPosCnt = (byte)(_hsyncCnt < 68 ? 160 - 2 : 160 - 4);
} else
{
_player0.Missile.HPosCnt = (byte)(_hsyncCnt < 76 ? 160 - 2 : 160 - 4);
}
}
else if (maskedAddr == 0x13) // RESM1
{
if (!_hmove.LateHBlankReset)
{
_player1.Missile.HPosCnt = (byte)(_hsyncCnt < 68 ? 160 - 2 : 160 - 4);
}
else
{
_player1.Missile.HPosCnt = (byte)(_hsyncCnt < 76 ? 160 - 2 : 160 - 4);
}
}
else if (maskedAddr == 0x14) // RESBL
{
if (!_hmove.LateHBlankReset)
{
_ball.HPosCnt = (byte)(_hsyncCnt < 68 ? 160 - 2 : 160 - 4);
}
else
{
_ball.HPosCnt = (byte)(_hsyncCnt < 76 ? 160 - 3 : 160 - 4);
}
}
else if (maskedAddr == 0x15) // AUDC0
{
WriteAudio(0, AudioRegister.AUDC, (byte)(value & 15));
@ -1006,28 +1310,30 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
}
else if (maskedAddr == 0x1B) // GRP0
{
_player0.Grp = value;
_player1.Dgrp = _player1.Grp;
prg0_val = value;
prg0_delay = 1;
}
else if (maskedAddr == 0x1C) // GRP1
{
_player1.Grp = value;
_player0.Dgrp = _player0.Grp;
prg1_val = value;
prg1_delay = 1;
// TODO: Find a game that uses this functionality and test it
_ball.Denabled = _ball.Enabled;
}
else if (maskedAddr == 0x1D) // ENAM0
{
_player0.Missile.Enabled = (value & 0x02) != 0;
enam0_val = (value & 0x02) != 0;
enam0_delay = 1;
}
else if (maskedAddr == 0x1E) // ENAM1
{
_player1.Missile.Enabled = (value & 0x02) != 0;
enam1_val = (value & 0x02) != 0;
enam1_delay = 1;
}
else if (maskedAddr == 0x1F) // ENABL
{
_ball.Enabled = (value & 0x02) != 0;
enamb_val = (value & 0x02) != 0;
enamb_delay = 1;
}
else if (maskedAddr == 0x20) // HMP0
{

1535
TIA.cs Normal file

File diff suppressed because it is too large Load Diff