From 1a7ac602327fe82945bc52e6b000196affc6060f Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Mon, 6 Feb 2017 00:30:39 +0100 Subject: [PATCH] Match NUSIZ during player decode or draw to real hardware. --- src/emucore/tia/Player.cxx | 222 ++++++++++++++----------------------- src/emucore/tia/Player.hxx | 8 +- 2 files changed, 90 insertions(+), 140 deletions(-) diff --git a/src/emucore/tia/Player.cxx b/src/emucore/tia/Player.cxx index 1ff6924c2..691b63d51 100644 --- a/src/emucore/tia/Player.cxx +++ b/src/emucore/tia/Player.cxx @@ -20,7 +20,6 @@ enum Count: Int8 { renderCounterOffset = -5, - renderCounterOffsetWide = -6 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -39,28 +38,25 @@ void Player::reset() myHmmClocks = 0; myCounter = 0; myIsMoving = false; - myWidth = 8; - myEffectiveWidth = 8; myIsRendering = false; myRenderCounter = 0; myPatternOld = 0; myPatternNew = 0; - myPattern = 0; myIsReflected = 0; myIsDelaying = false; myColor = myObjectColor = myDebugColor = 0; myDebugEnabled = false; collision = myCollisionMaskDisabled; - - updatePattern(); + myDivider = 1; + mySampleCounter = 0; + myDividerPending = 0; + myDividerChangeCounter = -1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::grp(uInt8 pattern) { myPatternNew = pattern; - - if (!myIsDelaying) updatePattern(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -73,37 +69,58 @@ void Player::hmp(uInt8 value) void Player::nusiz(uInt8 value) { const uInt8 masked = value & 0x07; - const uInt8 oldWidth = myWidth; - if (masked == 5) - myWidth = 16; - else if (masked == 7) - myWidth = 32; - else - myWidth = 8; + switch (masked) { + case 5: + myDividerPending = 2; + break; - 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 - // is required for a complete description (#63) - if (myIsRendering && myRenderCounter >= (8 - myWidth / 4 - 2) && oldWidth == 8 && myWidth != oldWidth) - 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++; + default: + myDividerPending = 1; + break; } - 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; - const Int8 renderCounterOffset = myWidth > 8 ? Count::renderCounterOffsetWide : Count::renderCounterOffset; - // This tries to account for the effects of RESP during draw counter decode as // described in Andrew Towers' notes. Still room for tuning.' if (myIsRendering && (myRenderCounter - renderCounterOffset) < 4) @@ -122,11 +137,7 @@ void Player::resp(uInt8 counter) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::refp(uInt8 value) { - const bool oldIsReflected = myIsReflected; - myIsReflected = (value & 0x08) > 0; - - if (myIsReflected != oldIsReflected) updatePattern(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -135,15 +146,12 @@ void Player::vdelp(uInt8 value) const bool oldIsDelaying = myIsDelaying; myIsDelaying = (value & 0x01) > 0; - - if (myIsDelaying != oldIsDelaying) updatePattern(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::toggleEnabled(bool enabled) { myIsSuppressed = !enabled; - updatePattern(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -197,11 +205,16 @@ bool Player::movementTick(uInt32 clock, bool apply) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::render() { - collision = ( - myIsRendering && - myRenderCounter >= 0 && - (myPattern & (1 << (myWidth - myRenderCounter - 1))) - ) ? myCollisionMaskEnabled : myCollisionMaskDisabled; + if (!myIsRendering || myRenderCounter < (myDivider > 1 ? 1 : 0)) { + collision = myCollisionMaskDisabled; + return; + } + + 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]) { myIsRendering = true; - myEffectiveWidth = myWidth; - myRenderCounter = myWidth > 8 ? Count::renderCounterOffsetWide : Count::renderCounterOffset; - } else if (myIsRendering && ++myRenderCounter >= myEffectiveWidth) { - myIsRendering = false; + mySampleCounter = 0; + myRenderCounter = Count::renderCounterOffset; + } else if (myIsRendering) { + 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; @@ -224,22 +254,20 @@ void Player::shufflePatterns() const uInt8 oldPatternOld = myPatternOld; myPatternOld = myPatternNew; - - if (myIsDelaying && oldPatternOld != myPatternOld) updatePattern(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Player::getRespClock() const { - switch (myWidth) + switch (myDivider) { - case 8: + case 1: return (myCounter + 160 - 5) % 160; - case 16: + case 2: return (myCounter + 160 - 9) % 160; - case 32: + case 4: return (myCounter + 160 - 12) % 160; 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() { diff --git a/src/emucore/tia/Player.hxx b/src/emucore/tia/Player.hxx index f5b009fb8..d9a6c6422 100644 --- a/src/emucore/tia/Player.hxx +++ b/src/emucore/tia/Player.hxx @@ -86,7 +86,6 @@ class Player : public Serializable private: - void updatePattern(); void applyColors(); private: @@ -102,17 +101,18 @@ class Player : public Serializable uInt8 myHmmClocks; uInt8 myCounter; bool myIsMoving; - uInt8 myWidth; - uInt8 myEffectiveWidth; bool myIsRendering; Int8 myRenderCounter; + uInt8 myDivider; + uInt8 myDividerPending; + uInt8 mySampleCounter; + Int8 myDividerChangeCounter; const uInt8* myDecodes; uInt8 myPatternOld; uInt8 myPatternNew; - uInt32 myPattern; bool myIsReflected; bool myIsDelaying;