mirror of https://github.com/stella-emu/stella.git
Match NUSIZ during player decode or draw to real hardware.
This commit is contained in:
parent
8b4096e1ef
commit
1a7ac60232
|
@ -20,7 +20,6 @@
|
||||||
|
|
||||||
enum Count: Int8 {
|
enum Count: Int8 {
|
||||||
renderCounterOffset = -5,
|
renderCounterOffset = -5,
|
||||||
renderCounterOffsetWide = -6
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -39,28 +38,25 @@ void Player::reset()
|
||||||
myHmmClocks = 0;
|
myHmmClocks = 0;
|
||||||
myCounter = 0;
|
myCounter = 0;
|
||||||
myIsMoving = false;
|
myIsMoving = false;
|
||||||
myWidth = 8;
|
|
||||||
myEffectiveWidth = 8;
|
|
||||||
myIsRendering = false;
|
myIsRendering = false;
|
||||||
myRenderCounter = 0;
|
myRenderCounter = 0;
|
||||||
myPatternOld = 0;
|
myPatternOld = 0;
|
||||||
myPatternNew = 0;
|
myPatternNew = 0;
|
||||||
myPattern = 0;
|
|
||||||
myIsReflected = 0;
|
myIsReflected = 0;
|
||||||
myIsDelaying = false;
|
myIsDelaying = false;
|
||||||
myColor = myObjectColor = myDebugColor = 0;
|
myColor = myObjectColor = myDebugColor = 0;
|
||||||
myDebugEnabled = false;
|
myDebugEnabled = false;
|
||||||
collision = myCollisionMaskDisabled;
|
collision = myCollisionMaskDisabled;
|
||||||
|
myDivider = 1;
|
||||||
updatePattern();
|
mySampleCounter = 0;
|
||||||
|
myDividerPending = 0;
|
||||||
|
myDividerChangeCounter = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Player::grp(uInt8 pattern)
|
void Player::grp(uInt8 pattern)
|
||||||
{
|
{
|
||||||
myPatternNew = pattern;
|
myPatternNew = pattern;
|
||||||
|
|
||||||
if (!myIsDelaying) updatePattern();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -73,37 +69,58 @@ void Player::hmp(uInt8 value)
|
||||||
void Player::nusiz(uInt8 value)
|
void Player::nusiz(uInt8 value)
|
||||||
{
|
{
|
||||||
const uInt8 masked = value & 0x07;
|
const uInt8 masked = value & 0x07;
|
||||||
const uInt8 oldWidth = myWidth;
|
|
||||||
|
|
||||||
if (masked == 5)
|
switch (masked) {
|
||||||
myWidth = 16;
|
case 5:
|
||||||
else if (masked == 7)
|
myDividerPending = 2;
|
||||||
myWidth = 32;
|
break;
|
||||||
else
|
|
||||||
myWidth = 8;
|
|
||||||
|
|
||||||
myDecodes = DrawCounterDecodes::get().playerDecodes()[masked];
|
case 7:
|
||||||
|
myDividerPending = 4;
|
||||||
|
break;
|
||||||
|
|
||||||
// This is an incomplete description of the effects seen in issues #87 and #82. More investigation
|
default:
|
||||||
// is required for a complete description (#63)
|
myDividerPending = 1;
|
||||||
if (myIsRendering && myRenderCounter >= (8 - myWidth / 4 - 2) && oldWidth == 8 && myWidth != oldWidth)
|
break;
|
||||||
myEffectiveWidth = oldWidth;
|
|
||||||
else
|
|
||||||
myEffectiveWidth = myWidth;
|
|
||||||
|
|
||||||
if (myRenderCounter >= myEffectiveWidth)
|
|
||||||
myIsRendering = false;
|
|
||||||
|
|
||||||
// NUSIZ during decode seems to affect the decoding logic. The rods in Meltdown
|
|
||||||
// are highly sensitive to this effect, and this seems to model it adequately.
|
|
||||||
if (myIsRendering && myRenderCounter < 0) {
|
|
||||||
if (myWidth > 8 && oldWidth == 8)
|
|
||||||
myRenderCounter += (myRenderCounter < -2 ? -1 : 1);
|
|
||||||
else if (myWidth == 8 && oldWidth > 8 && myRenderCounter < -3)
|
|
||||||
myRenderCounter++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldWidth != myWidth) updatePattern();
|
if (myIsRendering) {
|
||||||
|
|
||||||
|
switch ((myDivider << 4) | myDividerPending) {
|
||||||
|
case 0x12:
|
||||||
|
case 0x14:
|
||||||
|
if ((myRenderCounter - Count::renderCounterOffset) < 3)
|
||||||
|
myDivider = myDividerPending;
|
||||||
|
else
|
||||||
|
myDividerChangeCounter = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21:
|
||||||
|
case 0x41:
|
||||||
|
if ((myRenderCounter - Count::renderCounterOffset) < 3) {
|
||||||
|
myDivider = myDividerPending;
|
||||||
|
} else if ((myRenderCounter - Count::renderCounterOffset) < 5) {
|
||||||
|
myDivider = myDividerPending;
|
||||||
|
myRenderCounter--;
|
||||||
|
} else {
|
||||||
|
myDividerChangeCounter = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (myRenderCounter < 1)
|
||||||
|
myDivider = myDividerPending;
|
||||||
|
else
|
||||||
|
myDividerChangeCounter = (myDivider - (myRenderCounter - 1) % myDivider);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
myDivider = myDividerPending;
|
||||||
|
}
|
||||||
|
|
||||||
|
myDecodes = DrawCounterDecodes::get().playerDecodes()[masked];
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -111,8 +128,6 @@ void Player::resp(uInt8 counter)
|
||||||
{
|
{
|
||||||
myCounter = counter;
|
myCounter = counter;
|
||||||
|
|
||||||
const Int8 renderCounterOffset = myWidth > 8 ? Count::renderCounterOffsetWide : Count::renderCounterOffset;
|
|
||||||
|
|
||||||
// This tries to account for the effects of RESP during draw counter decode as
|
// This tries to account for the effects of RESP during draw counter decode as
|
||||||
// described in Andrew Towers' notes. Still room for tuning.'
|
// described in Andrew Towers' notes. Still room for tuning.'
|
||||||
if (myIsRendering && (myRenderCounter - renderCounterOffset) < 4)
|
if (myIsRendering && (myRenderCounter - renderCounterOffset) < 4)
|
||||||
|
@ -122,11 +137,7 @@ void Player::resp(uInt8 counter)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Player::refp(uInt8 value)
|
void Player::refp(uInt8 value)
|
||||||
{
|
{
|
||||||
const bool oldIsReflected = myIsReflected;
|
|
||||||
|
|
||||||
myIsReflected = (value & 0x08) > 0;
|
myIsReflected = (value & 0x08) > 0;
|
||||||
|
|
||||||
if (myIsReflected != oldIsReflected) updatePattern();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -135,15 +146,12 @@ void Player::vdelp(uInt8 value)
|
||||||
const bool oldIsDelaying = myIsDelaying;
|
const bool oldIsDelaying = myIsDelaying;
|
||||||
|
|
||||||
myIsDelaying = (value & 0x01) > 0;
|
myIsDelaying = (value & 0x01) > 0;
|
||||||
|
|
||||||
if (myIsDelaying != oldIsDelaying) updatePattern();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Player::toggleEnabled(bool enabled)
|
void Player::toggleEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
myIsSuppressed = !enabled;
|
myIsSuppressed = !enabled;
|
||||||
updatePattern();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -197,11 +205,16 @@ bool Player::movementTick(uInt32 clock, bool apply)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Player::render()
|
void Player::render()
|
||||||
{
|
{
|
||||||
collision = (
|
if (!myIsRendering || myRenderCounter < (myDivider > 1 ? 1 : 0)) {
|
||||||
myIsRendering &&
|
collision = myCollisionMaskDisabled;
|
||||||
myRenderCounter >= 0 &&
|
return;
|
||||||
(myPattern & (1 << (myWidth - myRenderCounter - 1)))
|
}
|
||||||
) ? myCollisionMaskEnabled : myCollisionMaskDisabled;
|
|
||||||
|
uInt8 pixel =
|
||||||
|
(myIsDelaying ? myPatternOld : myPatternNew) &
|
||||||
|
(1 << (!myIsReflected ? (7 - mySampleCounter) : mySampleCounter));
|
||||||
|
|
||||||
|
collision = (pixel > 0) ? myCollisionMaskEnabled : myCollisionMaskDisabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
@ -209,10 +222,27 @@ void Player::tick()
|
||||||
{
|
{
|
||||||
if (myDecodes[myCounter]) {
|
if (myDecodes[myCounter]) {
|
||||||
myIsRendering = true;
|
myIsRendering = true;
|
||||||
myEffectiveWidth = myWidth;
|
mySampleCounter = 0;
|
||||||
myRenderCounter = myWidth > 8 ? Count::renderCounterOffsetWide : Count::renderCounterOffset;
|
myRenderCounter = Count::renderCounterOffset;
|
||||||
} else if (myIsRendering && ++myRenderCounter >= myEffectiveWidth) {
|
} else if (myIsRendering) {
|
||||||
myIsRendering = false;
|
myRenderCounter++;
|
||||||
|
|
||||||
|
if (myDivider == 1) {
|
||||||
|
if (myRenderCounter > 0) {
|
||||||
|
mySampleCounter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (myRenderCounter >= 0 && myDividerChangeCounter >= 0 && myDividerChangeCounter-- == 0)
|
||||||
|
myDivider = myDividerPending;
|
||||||
|
} else {
|
||||||
|
if (myRenderCounter > 1 && (((myRenderCounter - 1) % myDivider) == 0))
|
||||||
|
mySampleCounter++;
|
||||||
|
|
||||||
|
if (myRenderCounter > 0 && myDividerChangeCounter >= 0 && myDividerChangeCounter-- == 0)
|
||||||
|
myDivider = myDividerPending;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mySampleCounter > 7) myIsRendering = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (++myCounter >= 160) myCounter = 0;
|
if (++myCounter >= 160) myCounter = 0;
|
||||||
|
@ -224,22 +254,20 @@ void Player::shufflePatterns()
|
||||||
const uInt8 oldPatternOld = myPatternOld;
|
const uInt8 oldPatternOld = myPatternOld;
|
||||||
|
|
||||||
myPatternOld = myPatternNew;
|
myPatternOld = myPatternNew;
|
||||||
|
|
||||||
if (myIsDelaying && oldPatternOld != myPatternOld) updatePattern();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
uInt8 Player::getRespClock() const
|
uInt8 Player::getRespClock() const
|
||||||
{
|
{
|
||||||
switch (myWidth)
|
switch (myDivider)
|
||||||
{
|
{
|
||||||
case 8:
|
case 1:
|
||||||
return (myCounter + 160 - 5) % 160;
|
return (myCounter + 160 - 5) % 160;
|
||||||
|
|
||||||
case 16:
|
case 2:
|
||||||
return (myCounter + 160 - 9) % 160;
|
return (myCounter + 160 - 9) % 160;
|
||||||
|
|
||||||
case 32:
|
case 4:
|
||||||
return (myCounter + 160 - 12) % 160;
|
return (myCounter + 160 - 12) % 160;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -247,84 +275,6 @@ uInt8 Player::getRespClock() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
void Player::updatePattern()
|
|
||||||
{
|
|
||||||
if (myIsSuppressed) {
|
|
||||||
myPattern = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uInt32 pattern = myIsDelaying ? myPatternOld : myPatternNew;
|
|
||||||
|
|
||||||
switch (myWidth)
|
|
||||||
{
|
|
||||||
case 8:
|
|
||||||
if (myIsReflected) {
|
|
||||||
myPattern =
|
|
||||||
((pattern & 0x01) << 7) |
|
|
||||||
((pattern & 0x02) << 5) |
|
|
||||||
((pattern & 0x04) << 3) |
|
|
||||||
((pattern & 0x08) << 1) |
|
|
||||||
((pattern & 0x10) >> 1) |
|
|
||||||
((pattern & 0x20) >> 3) |
|
|
||||||
((pattern & 0x40) >> 5) |
|
|
||||||
((pattern & 0x80) >> 7);
|
|
||||||
} else {
|
|
||||||
myPattern = pattern;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 16:
|
|
||||||
if (myIsReflected) {
|
|
||||||
myPattern =
|
|
||||||
((3 * (pattern & 0x01)) << 14) |
|
|
||||||
((3 * (pattern & 0x02)) << 11) |
|
|
||||||
((3 * (pattern & 0x04)) << 8) |
|
|
||||||
((3 * (pattern & 0x08)) << 5) |
|
|
||||||
((3 * (pattern & 0x10)) << 2) |
|
|
||||||
((3 * (pattern & 0x20)) >> 1) |
|
|
||||||
((3 * (pattern & 0x40)) >> 4) |
|
|
||||||
((3 * (pattern & 0x80)) >> 7);
|
|
||||||
} else {
|
|
||||||
myPattern =
|
|
||||||
((3 * (pattern & 0x01))) |
|
|
||||||
((3 * (pattern & 0x02)) << 1) |
|
|
||||||
((3 * (pattern & 0x04)) << 2) |
|
|
||||||
((3 * (pattern & 0x08)) << 3) |
|
|
||||||
((3 * (pattern & 0x10)) << 4) |
|
|
||||||
((3 * (pattern & 0x20)) << 5) |
|
|
||||||
((3 * (pattern & 0x40)) << 6) |
|
|
||||||
((3 * (pattern & 0x80)) << 7);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 32:
|
|
||||||
if (myIsReflected) {
|
|
||||||
myPattern =
|
|
||||||
((0xF * (pattern & 0x01)) << 28) |
|
|
||||||
((0xF * (pattern & 0x02)) << 23) |
|
|
||||||
((0xF * (pattern & 0x04)) << 18) |
|
|
||||||
((0xF * (pattern & 0x08)) << 13) |
|
|
||||||
((0xF * (pattern & 0x10)) << 8) |
|
|
||||||
((0xF * (pattern & 0x20)) << 3) |
|
|
||||||
((0xF * (pattern & 0x40)) >> 2) |
|
|
||||||
((0xF * (pattern & 0x80)) >> 7);
|
|
||||||
} else {
|
|
||||||
myPattern =
|
|
||||||
((0xF * (pattern & 0x01))) |
|
|
||||||
((0xF * (pattern & 0x02)) << 3) |
|
|
||||||
((0xF * (pattern & 0x04)) << 6) |
|
|
||||||
((0xF * (pattern & 0x08)) << 9) |
|
|
||||||
((0xF * (pattern & 0x10)) << 12) |
|
|
||||||
((0xF * (pattern & 0x20)) << 15) |
|
|
||||||
((0xF * (pattern & 0x40)) << 18) |
|
|
||||||
((0xF * (pattern & 0x80)) << 21);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
void Player::applyColors()
|
void Player::applyColors()
|
||||||
{
|
{
|
||||||
|
|
|
@ -86,7 +86,6 @@ class Player : public Serializable
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void updatePattern();
|
|
||||||
void applyColors();
|
void applyColors();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -102,17 +101,18 @@ class Player : public Serializable
|
||||||
uInt8 myHmmClocks;
|
uInt8 myHmmClocks;
|
||||||
uInt8 myCounter;
|
uInt8 myCounter;
|
||||||
bool myIsMoving;
|
bool myIsMoving;
|
||||||
uInt8 myWidth;
|
|
||||||
uInt8 myEffectiveWidth;
|
|
||||||
|
|
||||||
bool myIsRendering;
|
bool myIsRendering;
|
||||||
Int8 myRenderCounter;
|
Int8 myRenderCounter;
|
||||||
|
uInt8 myDivider;
|
||||||
|
uInt8 myDividerPending;
|
||||||
|
uInt8 mySampleCounter;
|
||||||
|
Int8 myDividerChangeCounter;
|
||||||
|
|
||||||
const uInt8* myDecodes;
|
const uInt8* myDecodes;
|
||||||
|
|
||||||
uInt8 myPatternOld;
|
uInt8 myPatternOld;
|
||||||
uInt8 myPatternNew;
|
uInt8 myPatternNew;
|
||||||
uInt32 myPattern;
|
|
||||||
|
|
||||||
bool myIsReflected;
|
bool myIsReflected;
|
||||||
bool myIsDelaying;
|
bool myIsDelaying;
|
||||||
|
|
Loading…
Reference in New Issue