diff --git a/Todo.txt b/Todo.txt index e8ec27e6c..7443c6600 100644 --- a/Todo.txt +++ b/Todo.txt @@ -16,8 +16,15 @@ If you would like to contribute to Stella's development then find something on the list below and send email to Bradford Mott at bwmott@acm.org or Stephen Anthony at stephena@users.sourceforge.net. - * Add new TIA infrastructure with improved HMOVE emulation, including - fixes for (possibly) incorrect VSYNC handling in Q-Bert. + * TIA infrastructure: further improve 'illegal' HMOVE emulation to fix + problems in several homebrew ROMs. + + * TIA infrastructure: improve emulation of writes to NUSIZx while graphics + are currently being drawn. + + * TIA infrastructure: fix incorrect VSYNC handling in Q-Bert. + + * TIA infrastructure: add emulation of RSYNC instruction. * Look into adding Blargg NTSC filtering (perhaps as a GLSL program). diff --git a/src/debugger/TIADebug.cxx b/src/debugger/TIADebug.cxx index f40d52dc9..741a9328f 100644 --- a/src/debugger/TIADebug.cxx +++ b/src/debugger/TIADebug.cxx @@ -26,14 +26,14 @@ TIADebug::TIADebug(Debugger& dbg, Console& console) : DebuggerSystem(dbg, console), myTIA(console.tia()) { - nusizStrings[0] = "size=8 copy=1"; - nusizStrings[1] = "size=8 copy=2 spac=8"; - nusizStrings[2] = "size=8 copy=2 spac=$18"; - nusizStrings[3] = "size=8 copy=3 spac=8"; - nusizStrings[4] = "size=8 copy=2 spac=$38"; - nusizStrings[5] = "size=$10 copy=1"; - nusizStrings[6] = "size=8 copy=3 spac=$18"; - nusizStrings[7] = "size=$20 copy=1"; + nusizStrings[0] = "1 copy"; + nusizStrings[1] = "2 copies - close (8)"; + nusizStrings[2] = "2 copies - med (24)"; + nusizStrings[3] = "3 copies - close (8)"; + nusizStrings[4] = "2 copies - wide (56)"; + nusizStrings[5] = "2x (16) sized player"; + nusizStrings[6] = "3 copies - med (24)"; + nusizStrings[7] = "4x (32) sized player"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/debugger/TIADebug.hxx b/src/debugger/TIADebug.hxx index 158282de4..47c12a88a 100644 --- a/src/debugger/TIADebug.hxx +++ b/src/debugger/TIADebug.hxx @@ -33,54 +33,6 @@ typedef int (TIADebug::*TIADEBUG_INT_METHOD)(); // call the pointed-to method on the (global) debugger object. #define CALL_TIADEBUG_METHOD(method) ( ( Debugger::debugger().tiaDebug().*method)() ) -enum TIALabel { - VSYNC = 0, - VBLANK, - WSYNC, - RSYNC, - NUSIZ0, - NUSIZ1, - COLUP0, - COLUP1, - COLUPF, // $08 - COLUBK, - CTRLPF, - REFP0, - REFP1, - PF0, - PF1, - PF2, - RESP0, // $10 - RESP1, - RESM0, - RESM1, - RESBL, - AUDC0, - AUDC1, - AUDF0, - AUDF1, // $18 - AUDV0, - AUDV1, - GRP0, - GRP1, - ENAM0, - ENAM1, - ENABL, - HMP0, // $20 - HMP1, - HMM0, - HMM1, - HMBL, - VDELP0, - VDELP1, - VDELBL, - RESMP0, // $28 - RESMP1, - HMOVE, - HMCLR, - CXCLR // $2C -}; - // Indices for various IntArray in TiaState enum { P0, P1, M0, M1, BL diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index ff70f9ea8..c55ff3608 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -694,7 +694,7 @@ void Console::setControllers(const string& rommd5) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Console::toggleTIABit(TIA::TIABit bit, const string& bitname, bool show) const +void Console::toggleTIABit(TIABit bit, const string& bitname, bool show) const { bool result = myTIA->toggleBit(bit); string message = bitname + (result ? " enabled" : " disabled"); diff --git a/src/emucore/Console.hxx b/src/emucore/Console.hxx index dab61a0ac..25c8f2998 100644 --- a/src/emucore/Console.hxx +++ b/src/emucore/Console.hxx @@ -256,12 +256,12 @@ class Console : public Serializable /** Toggles the TIA bit specified in the method name. */ - void toggleP0Bit() const { toggleTIABit(TIA::P0, "P0"); } - void toggleP1Bit() const { toggleTIABit(TIA::P1, "P1"); } - void toggleM0Bit() const { toggleTIABit(TIA::M0, "M0"); } - void toggleM1Bit() const { toggleTIABit(TIA::M1, "M1"); } - void toggleBLBit() const { toggleTIABit(TIA::BL, "BL"); } - void togglePFBit() const { toggleTIABit(TIA::PF, "PF"); } + void toggleP0Bit() const { toggleTIABit(P0Bit, "P0"); } + void toggleP1Bit() const { toggleTIABit(P1Bit, "P1"); } + void toggleM0Bit() const { toggleTIABit(M0Bit, "M0"); } + void toggleM1Bit() const { toggleTIABit(M1Bit, "M1"); } + void toggleBLBit() const { toggleTIABit(BLBit, "BL"); } + void togglePFBit() const { toggleTIABit(PFBit, "PF"); } void enableBits(bool enable) const; private: @@ -270,7 +270,7 @@ class Console : public Serializable */ void setControllers(const string& rommd5); - void toggleTIABit(TIA::TIABit bit, const string& bitname, bool show = true) const; + void toggleTIABit(TIABit bit, const string& bitname, bool show = true) const; /** Loads a user-defined palette file (from OSystem::paletteFile), filling the diff --git a/src/emucore/DefProps.hxx b/src/emucore/DefProps.hxx index a5009fe45..03445e5dc 100644 --- a/src/emucore/DefProps.hxx +++ b/src/emucore/DefProps.hxx @@ -26,7 +26,7 @@ regenerated and the application recompiled. */ -#define DEF_PROPS_SIZE 3245 +#define DEF_PROPS_SIZE 3246 static const char* DefProps[DEF_PROPS_SIZE][20] = { { "000509d1ed2b8d30a9d94be1b3b5febb", "Greg Zumwalt", "", "Jungle Jane (2003) (Greg Zumwalt) (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, @@ -925,6 +925,7 @@ static const char* DefProps[DEF_PROPS_SIZE][20] = { { "45a095645696a217e416e4bd2baea723", "Digivision", "", "Snoopy (Digivision)", "AKA Snoopy and the Red Baron", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "45a4f55bb9a5083d470ad479afd8bca2", "CommaVid, Joseph Biel", "", "Frog Demo (1983) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "45beef9da1a7e45f37f3f445f769a0b3", "Atari, Suki Lee", "CX2658", "Math Gran Prix (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, + { "45c4413dd703b9cfea49a13709d560eb", "Jone Yuan Telephonic Enterprise Co", "", "Challenge of.... Nexar, The (Jone Yuan) (Hack)", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "45cb0f41774b78def53331e4c3bf3362", "Carrere Video, Roger Booth, Sylvia Day, Todd Marshall, Wes Trager, Henry Will - Teldec", "USC1007", "Octopus (1983) (Carrere Video) (PAL)", "AKA Name This Game", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4605a00f5b44a9cbd5803a7a55de150e", "Coleco, Ed Temple", "", "Cabbage Patch Kids (07-03-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "461029ab23800833e9645be3e472d470", "", "", "Combat TC (v0.1)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, diff --git a/src/emucore/TIA.cxx b/src/emucore/TIA.cxx index 9806894d5..65290955c 100644 --- a/src/emucore/TIA.cxx +++ b/src/emucore/TIA.cxx @@ -35,8 +35,6 @@ #define HBLANK 68 #define USE_MMR_LATCHES -static int P0suppress = 0; -static int P1suppress = 0; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TIA::TIA(Console& console, Sound& sound, Settings& settings) @@ -118,8 +116,9 @@ void TIA::reset() // Reset the sound device mySound.reset(); - // Currently no objects are enabled + // Currently no objects are enabled or selectively disabled myEnabledObjects = 0; + myDisabledObjects = 0; // Some default values for the registers myVSYNC = myVBLANK = 0; @@ -155,6 +154,8 @@ void TIA::reset() myMotionClockM1 = 0; myMotionClockBL = 0; + mySuppressP0 = mySuppressP1 = 0; + myHMP0mmr = myHMP1mmr = myHMM0mmr = myHMM1mmr = myHMBLmmr = false; myCurrentHMOVEPos = myPreviousHMOVEPos = 0x7FFFFFFF; @@ -302,6 +303,7 @@ bool TIA::save(Serializer& out) const out.putInt(myVSYNCFinishClock); out.putByte((char)myEnabledObjects); + out.putByte((char)myDisabledObjects); out.putByte((char)myVSYNC); out.putByte((char)myVBLANK); @@ -340,14 +342,6 @@ bool TIA::save(Serializer& out) const out.putByte((char)myCurrentGRP0); out.putByte((char)myCurrentGRP1); -// pointers -// myCurrentBLMask = TIATables::BLMask[0][0]; -// myCurrentM0Mask = TIATables::MxMask[0][0][0]; -// myCurrentM1Mask = TIATables::MxMask[0][0][0]; -// myCurrentP0Mask = TIATables::PxMask[0][0][0]; -// myCurrentP1Mask = TIATables::PxMask[0][0][0]; -// myCurrentPFMask = TIATables::PFMask[0]; - out.putBool(myDumpEnabled); out.putInt(myDumpDisabledCycle); @@ -363,6 +357,14 @@ bool TIA::save(Serializer& out) const out.putInt(myMotionClockM1); out.putInt(myMotionClockBL); + out.putInt(myStartP0); + out.putInt(myStartP1); + out.putInt(myStartM0); + out.putInt(myStartM1); + + out.putByte(mySuppressP0); + out.putByte(mySuppressP1); + out.putBool(myHMP0mmr); out.putBool(myHMP1mmr); out.putBool(myHMM0mmr); @@ -411,6 +413,7 @@ bool TIA::load(Serializer& in) myVSYNCFinishClock = (Int32) in.getInt(); myEnabledObjects = (uInt8) in.getByte(); + myDisabledObjects = (uInt8) in.getByte(); myVSYNC = (uInt8) in.getByte(); myVBLANK = (uInt8) in.getByte(); @@ -449,14 +452,6 @@ bool TIA::load(Serializer& in) myCurrentGRP0 = (uInt8) in.getByte(); myCurrentGRP1 = (uInt8) in.getByte(); -// pointers -// myCurrentBLMask = TIATables::BLMask[0][0]; -// myCurrentM0Mask = TIATables::MxMask[0][0][0]; -// myCurrentM1Mask = TIATables::MxMask[0][0][0]; -// myCurrentP0Mask = TIATables::PxMask[0][0][0]; -// myCurrentP1Mask = TIATables::PxMask[0][0][0]; -// myCurrentPFMask = TIATables::PFMask[0]; - myDumpEnabled = in.getBool(); myDumpDisabledCycle = (Int32) in.getInt(); @@ -472,6 +467,14 @@ bool TIA::load(Serializer& in) myMotionClockM1 = (Int32) in.getInt(); myMotionClockBL = (Int32) in.getInt(); + myStartP0 = (Int32) in.getInt(); + myStartP1 = (Int32) in.getInt(); + myStartM0 = (Int32) in.getInt(); + myStartM1 = (Int32) in.getInt(); + + mySuppressP0 = (uInt8) in.getByte(); + mySuppressP1 = (uInt8) in.getByte(); + myHMP0mmr = in.getBool(); myHMP1mmr = in.getBool(); myHMM0mmr = in.getBool(); @@ -488,7 +491,8 @@ bool TIA::load(Serializer& in) mySound.load(in); // Reset TIA bits to be on - enableBits(true); +// TODO - should we enable this, or leave it to the user? +// enableBits(true); } catch(char *msg) { @@ -672,6 +676,29 @@ inline void TIA::endFrame() myFrameGreyed = false; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool TIA::enableBit(TIABit b, bool mode, bool flip) +{ + // If flip is enabled, we ignore mode and calculate our own + if(flip) mode = !(myDisabledObjects & b); + + if(mode) myDisabledObjects |= b; + else myDisabledObjects &= ~b; + + return mode; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIA::enableBits(bool mode) +{ + enableBit(P0Bit, mode); + enableBit(P1Bit, mode); + enableBit(M0Bit, mode); + enableBit(M1Bit, mode); + enableBit(BLBit, mode); + enableBit(PFBit, mode); +} + #ifdef DEBUGGER_SUPPORT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::updateScanline() @@ -771,9 +798,9 @@ inline void TIA::updateFrameScanline(uInt32 clocksToUpdate, uInt32 hpos) myCurrentBLMask = &TIATables::BLMask[myPOSBL & 0x03] [(myCTRLPF & 0x30) >> 4][160 - (myPOSBL & 0xFC)]; myCurrentP0Mask = &TIATables::PxMask[myPOSP0 & 0x03] - [P0suppress][myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFC)]; + [mySuppressP0][myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFC)]; myCurrentP1Mask = &TIATables::PxMask[myPOSP1 & 0x03] - [P1suppress][myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFC)]; + [mySuppressP1][myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFC)]; myCurrentM0Mask = &TIATables::MxMask[myPOSM0 & 0x03] [myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)]; myCurrentM1Mask = &TIATables::MxMask[myPOSM1 & 0x03] @@ -1322,18 +1349,19 @@ inline void TIA::updateFrameScanline(uInt32 clocksToUpdate, uInt32 hpos) { for(; myFramePointer < ending; ++myFramePointer, ++hpos) { - uInt8 enabled = (myPF & myCurrentPFMask[hpos]) ? PFBit : 0; + uInt8 enabled = ((myEnabledObjects & PFBit) && + (myPF & myCurrentPFMask[hpos])) ? PFBit : 0; if((myEnabledObjects & BLBit) && myCurrentBLMask[hpos]) enabled |= BLBit; - if(myCurrentGRP1 & myCurrentP1Mask[hpos]) + if((myEnabledObjects & P1Bit) && (myCurrentGRP1 & myCurrentP1Mask[hpos])) enabled |= P1Bit; if((myEnabledObjects & M1Bit) && myCurrentM1Mask[hpos]) enabled |= M1Bit; - if(myCurrentGRP0 & myCurrentP0Mask[hpos]) + if((myEnabledObjects & P0Bit) && (myCurrentGRP0 & myCurrentP0Mask[hpos])) enabled |= P0Bit; if((myEnabledObjects & M0Bit) && myCurrentM0Mask[hpos]) @@ -1363,6 +1391,8 @@ void TIA::updateFrame(Int32 clock) if(clock > myClockStopDisplay) clock = myClockStopDisplay; +//cerr << "updateFrame: " << clock << endl; + // Determine how many scanlines to process // It's easier to think about this in scanlines rather than color clocks uInt32 startLine = (myClockAtLastUpdate - myClockWhenFrameStarted) / 228; @@ -1458,8 +1488,16 @@ void TIA::updateFrame(Int32 clock) // Update as much of the scanline as we can if(clocksToUpdate != 0) + { + // Selectively disable all bits we don't wish to draw + uInt8 oldEnabled = myEnabledObjects; + myEnabledObjects &= myDisabledObjects; + updateFrameScanline(clocksToUpdate, clocksFromStartOfScanLine - HBLANK); + myEnabledObjects = oldEnabled; + } + // Handle HMOVE blanks if they are enabled if(myHMOVEBlankEnabled && (startOfScanLine < HBLANK + 8) && (clocksFromStartOfScanLine < (HBLANK + 8))) @@ -1480,8 +1518,7 @@ void TIA::updateFrame(Int32 clock) // TODO: These should be reset right after the first copy of the player // has passed. However, for now we'll just reset at the end of the // scanline since the other way would be to slow (01/21/99). -P0suppress = 0; -P1suppress = 0; + mySuppressP0 = mySuppressP1 = 0; } } } @@ -1499,7 +1536,6 @@ inline void TIA::waitHorizontalSync() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::greyOutFrame() { -cerr << "greyOutFrame(): scanlines = " << scanlines() << endl; uInt32 c = scanlines(); if(c < myFrameYStart) c = myFrameYStart; if(c > (myFrameHeight + myFrameYStart)) @@ -1729,17 +1765,19 @@ void TIA::poke(uInt16 addr, uInt8 value) case NUSIZ0: // Number-size of player-missle 0 { -//cerr << "NUSIZ0 set: " << (int)myNUSIZ0 << " => " << (int)value << " @ " << (clock + delay) << ", p0 pos = " << myPOSP0 << endl; + // TODO - 08-11-2009: determine correct delay instead of always + // using '8'. myNUSIZ0 = value; -P0suppress = 0; + mySuppressP0 = 0; break; } case NUSIZ1: // Number-size of player-missle 1 { -//cerr << "NUSIZ1 set: " << (int)myNUSIZ1 << " => " << (int)value << " @ " << (clock + delay) << endl; + // TODO - 08-11-2009: determine correct delay instead of always + // using '8'. myNUSIZ1 = value; -P1suppress = 0; + mySuppressP1 = 0; break; } @@ -1833,7 +1871,7 @@ P1suppress = 0; { myPF = (myPF & 0x000FFFF0) | ((value >> 4) & 0x0F); - if(myBitEnabled[TIA::PF] == 0x00 || myPF == 0) + if(myPF == 0) myEnabledObjects &= ~PFBit; else myEnabledObjects |= PFBit; @@ -1845,7 +1883,7 @@ P1suppress = 0; { myPF = (myPF & 0x000FF00F) | ((uInt32)value << 4); - if(myBitEnabled[TIA::PF] == 0x00 || myPF == 0) + if(myPF == 0) myEnabledObjects &= ~PFBit; else myEnabledObjects |= PFBit; @@ -1857,7 +1895,7 @@ P1suppress = 0; { myPF = (myPF & 0x00000FFF) | ((uInt32)value << 12); - if(myBitEnabled[TIA::PF] == 0x00 || myPF == 0) + if(myPF == 0) myEnabledObjects &= ~PFBit; else myEnabledObjects |= PFBit; @@ -1882,38 +1920,33 @@ P1suppress = 0; newx = hpos < -2 ? 3 : ((hpos + 5) % 160); applyPreviousHMOVEMotion(hpos, newx, myHMP0); } - if(newx != myPOSP0) + if(myPOSP0 != newx) { -// myPOSP0 = newx; -// myStartP0 = 0; - } + // Find out under what condition the player is being reset + delay = TIATables::PxPosResetWhen[myNUSIZ0 & 7][myPOSP0][newx]; - // Find out under what condition the player is being reset - Int8 when = TIATables::PxPosResetWhen[myNUSIZ0 & 7][myPOSP0][newx]; + switch(delay) + { + // Player is being reset during the display of one of its copies + case 1: + // TODO - 08-20-2009: determine whether we really need to update + // the frame here, and also come up with a way to eliminate the + // 200KB PxPosResetWhen table. + updateFrame(clock + 11); + mySuppressP0 = 1; + break; - // Player is being reset during the display of one of its copies - if(when == 1) - { - // So we go ahead and update the display before moving the player - // TODO: The 11 should depend on how much of the player has already - // been displayed. Probably change table to return the amount to - // delay by instead of just 1 (01/21/99). -// updateFrame(clock + 11); + // Player is being reset in neither the delay nor display section + case 0: + mySuppressP0 = 1; + break; + // Player is being reset during the delay section of one of its copies + case -1: + mySuppressP0 = 0; + break; + } myPOSP0 = newx; -P0suppress = 1; - } - // Player is being reset in neither the delay nor display section - else if(when == 0) - { - myPOSP0 = newx; -P0suppress = 1; - } - // Player is being reset during the delay section of one of its copies - else if(when == -1) - { - myPOSP0 = newx; -P0suppress = 0; } break; } @@ -1935,38 +1968,33 @@ P0suppress = 0; newx = hpos < -2 ? 3 : ((hpos + 5) % 160); applyPreviousHMOVEMotion(hpos, newx, myHMP1); } - if(newx != myPOSP1) + if(myPOSP1 != newx) { -// myPOSP1 = newx; -// myStartP1 = 0; - } + // Find out under what condition the player is being reset + delay = TIATables::PxPosResetWhen[myNUSIZ1 & 7][myPOSP1][newx]; - // Find out under what condition the player is being reset - Int8 when = TIATables::PxPosResetWhen[myNUSIZ1 & 7][myPOSP1][newx]; + switch(delay) + { + // Player is being reset during the display of one of its copies + case 1: + // TODO - 08-20-2009: determine whether we really need to update + // the frame here, and also come up with a way to eliminate the + // 200KB PxPosResetWhen table. + updateFrame(clock + 11); + mySuppressP1 = 1; + break; - // Player is being reset during the display of one of its copies - if(when == 1) - { - // So we go ahead and update the display before moving the player - // TODO: The 11 should depend on how much of the player has already - // been displayed. Probably change table to return the amount to - // delay by instead of just 1 (01/21/99). -// updateFrame(clock + 11); + // Player is being reset in neither the delay nor display section + case 0: + mySuppressP1 = 1; + break; + // Player is being reset during the delay section of one of its copies + case -1: + mySuppressP1 = 0; + break; + } myPOSP1 = newx; -P1suppress = 1; - } - // Player is being reset in neither the delay nor display section - else if(when == 0) - { - myPOSP1 = newx; -P1suppress = 1; - } - // Player is being reset during the delay section of one of its copies - else if(when == -1) - { - myPOSP1 = newx; -P1suppress = 0; } break; } @@ -1990,7 +2018,6 @@ P1suppress = 0; } if(newx != myPOSM0) { - // myStartM0 = skipM0delay ? 1 : 0; myPOSM0 = newx; } break; @@ -2015,7 +2042,6 @@ P1suppress = 0; } if(newx != myPOSM1) { - // myStartM1 = skipM1delay ? 1 : 0; myPOSM1 = newx; } break; @@ -2085,7 +2111,7 @@ P1suppress = 0; case GRP0: // Graphics Player 0 { // Set player 0 graphics - myGRP0 = value & myBitEnabled[TIA::P0]; + myGRP0 = value; // Copy player 1 graphics into its delayed register myDGRP1 = myGRP1; @@ -2115,7 +2141,7 @@ P1suppress = 0; case GRP1: // Graphics Player 1 { // Set player 1 graphics - myGRP1 = value & myBitEnabled[TIA::P1]; + myGRP1 = value; // Copy player 0 graphics into its delayed register myDGRP0 = myGRP0; @@ -2152,7 +2178,7 @@ P1suppress = 0; case ENAM0: // Enable Missile 0 graphics { - myENAM0 = (value & 0x02) & myBitEnabled[TIA::M0]; + myENAM0 = value & 0x02; if(myENAM0 && !myRESMP0) myEnabledObjects |= M0Bit; @@ -2163,7 +2189,7 @@ P1suppress = 0; case ENAM1: // Enable Missile 1 graphics { - myENAM1 = (value & 0x02) & myBitEnabled[TIA::M1]; + myENAM1 = value & 0x02; if(myENAM1 && !myRESMP1) myEnabledObjects |= M1Bit; @@ -2174,7 +2200,7 @@ P1suppress = 0; case ENABL: // Enable Ball graphics { - myENABL = (value & 0x02) & myBitEnabled[TIA::BL]; + myENABL = value & 0x02; if(myVDELBL ? myDENABL : myENABL) myEnabledObjects |= BLBit; @@ -2397,8 +2423,7 @@ P1suppress = 0; if(myPOSM1 < 0) { myPOSM1 += 160; } myPOSM1 %= 160; if(myPOSBL < 0) { myPOSBL += 160; } myPOSBL %= 160; -P0suppress = 0; -P1suppress = 0; + mySuppressP0 = mySuppressP1 = 0; break; } diff --git a/src/emucore/TIA.hxx b/src/emucore/TIA.hxx index 52e081949..75bf11630 100644 --- a/src/emucore/TIA.hxx +++ b/src/emucore/TIA.hxx @@ -26,6 +26,7 @@ class Settings; #include "Sound.hxx" #include "Device.hxx" #include "System.hxx" +#include "TIATables.hxx" /** This class is a device that emulates the Television Interface Adapator @@ -212,37 +213,28 @@ class TIA : public Device inline uInt32 scanlines() const { return ((mySystem->cycles() * 3) - myClockWhenFrameStarted) / 228; } - enum TIABit { - P0, // Descriptor for Player 0 Bit - P1, // Descriptor for Player 1 Bit - M0, // Descriptor for Missle 0 Bit - M1, // Descriptor for Missle 1 Bit - BL, // Descriptor for Ball Bit - PF // Descriptor for Playfield Bit - }; - /** - Enables/disables the specified TIA bit. + Enables/disables the specified TIA bit. If flip is true, ignore the + given mode and instead toggle/flip the specified TIA bit. @return Whether the bit was enabled or disabled */ - void enableBit(TIABit b, bool mode) { myBitEnabled[b] = mode ? 0xff : 0x00; } + bool enableBit(TIABit b, bool mode, bool flip = false); /** - Toggles the specified TIA bit. + Toggles the specified TIA bit. This is a convenience wrapper + around enableBit when flipping a bit. @return Whether the bit was enabled or disabled */ - bool toggleBit(TIABit b) - { myBitEnabled[b] = myBitEnabled[b] == 0xff ? 0x00 : 0xff; return myBitEnabled[b]; } + bool toggleBit(TIABit b) { return enableBit(b, true, true); } /** Enables/disables all TIABit bits. @param mode Whether to enable or disable all bits */ - void enableBits(bool mode) - { for(uInt8 i = 0; i < 6; ++i) myBitEnabled[i] = mode ? 0xff : 0x00; } + void enableBits(bool mode); #ifdef DEBUGGER_SUPPORT /** @@ -442,6 +434,11 @@ class TIA : public Device Int32 myStartM0; Int32 myStartM1; + // Index into the player mask arrays indicating whether display + // of the first copy should be suppressed + uInt8 mySuppressP0; + uInt8 mySuppressP1; + // Latches for 'more motion required' as described in A. Towers TIA // Hardware Notes bool myHMP0mmr; @@ -502,9 +499,9 @@ class TIA : public Device uInt8 myEnabledObjects; // Determines whether specified bits (from TIABit) are enabled or disabled - // Each value is and'ed with the appropriate register, so the valid values - // are 0x00 or 0xff; - uInt8 myBitEnabled[6]; + // This is and'ed with the enabled objects each scanline to mask out any + // objects we don't want to be processed + uInt8 myDisabledObjects; // Indicates if color loss should be enabled or disabled. Color loss // occurs on PAL (and maybe SECAM) systems when the previous frame diff --git a/src/emucore/TIATables.cxx b/src/emucore/TIATables.cxx index ceefd8f19..863b5e5fc 100644 --- a/src/emucore/TIATables.cxx +++ b/src/emucore/TIATables.cxx @@ -434,7 +434,7 @@ void TIATables::buildPxPosResetWhenTable() if((newx >= oldx) && (newx < (oldx + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) + else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; break; @@ -444,7 +444,7 @@ void TIATables::buildPxPosResetWhenTable() else if((newx >= (oldx + 16)) && (newx < (oldx + 16 + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) + else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; else if((newx >= oldx + 16 + 4) && (newx < (oldx + 16 + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; @@ -456,7 +456,7 @@ void TIATables::buildPxPosResetWhenTable() else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) + else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; @@ -470,7 +470,7 @@ void TIATables::buildPxPosResetWhenTable() else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) + else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; else if((newx >= oldx + 16 + 4) && (newx < (oldx + 16 + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; @@ -484,7 +484,7 @@ void TIATables::buildPxPosResetWhenTable() else if((newx >= (oldx + 64)) && (newx < (oldx + 64 + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) + else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; else if((newx >= oldx + 64 + 4) && (newx < (oldx + 64 + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; @@ -494,7 +494,7 @@ void TIATables::buildPxPosResetWhenTable() if((newx >= oldx) && (newx < (oldx + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - if((newx >= oldx + 4) && (newx < (oldx + 4 + 16))) + else if((newx >= oldx + 4) && (newx < (oldx + 4 + 16))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; break; @@ -506,7 +506,7 @@ void TIATables::buildPxPosResetWhenTable() else if((newx >= (oldx + 64)) && (newx < (oldx + 64 + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) + else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; @@ -518,7 +518,7 @@ void TIATables::buildPxPosResetWhenTable() if((newx >= oldx) && (newx < (oldx + 4))) PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - if((newx >= oldx + 4) && (newx < (oldx + 4 + 32))) + else if((newx >= oldx + 4) && (newx < (oldx + 4 + 32))) PxPosResetWhen[nusiz][oldx][newx % 160] = 1; break; } @@ -549,8 +549,8 @@ uInt8 TIATables::DisabledMask[640]; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Int16 TIATables::PokeDelay[64] = { - 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, -1, -1, -1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, + 0, 1, 0, 0, 8, 8, 0, 0, 0, 0, 0, 1, 1, -1, -1, -1, + 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; @@ -570,6 +570,7 @@ const bool TIATables::HMOVEBlankEnableCycles[76] = { false, false, false, false, false, true // 70 }; +#if 0 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Int32 TIATables::CompleteMotion[76][16] = { { 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK @@ -649,6 +650,7 @@ const Int32 TIATables::CompleteMotion[76][16] = { {-8, -9,-10,-11,-12,-13,-14,-15, 0, -1, -2, -3, -4, -5, -6, -7}, { 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1} // HBLANK }; +#endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIATables::PxMask[4][2][8][320]; diff --git a/src/emucore/TIATables.hxx b/src/emucore/TIATables.hxx index 4b6e3198d..9c1bf73f3 100644 --- a/src/emucore/TIATables.hxx +++ b/src/emucore/TIATables.hxx @@ -21,7 +21,7 @@ #include "bspf.hxx" -enum { +enum TIABit { P0Bit = 0x01, // Bit for Player 0 M0Bit = 0x02, // Bit for Missle 0 P1Bit = 0x04, // Bit for Player 1 @@ -32,7 +32,7 @@ enum { PriorityBit = 0x80 // Bit for Playfield priority }; -enum +enum CollisionBit { Cx_M0P1 = 1 << 0, // Missle0 - Player1 collision Cx_M0P0 = 1 << 1, // Missle0 - Player0 collision @@ -52,7 +52,7 @@ enum }; // TIA Write/Read register names -enum { +enum TIARegister { VSYNC = 0x00, // Write: vertical sync set-clear (D1) VBLANK = 0x01, // Write: vertical blank set-clear (D7-6,D1) WSYNC = 0x02, // Write: wait for leading edge of hrz. blank (strobe) @@ -140,9 +140,11 @@ class TIATables // Indicates the update delay associated with poking at a TIA address static const Int16 PokeDelay[64]; +#if 0 // Used to convert value written in a motion register into // its internal representation static const Int32 CompleteMotion[76][16]; +#endif // Indicates if HMOVE blanks should occur for the corresponding cycle static const bool HMOVEBlankEnableCycles[76]; diff --git a/src/emucore/stella.pro b/src/emucore/stella.pro index d049e7f9f..30b432428 100644 --- a/src/emucore/stella.pro +++ b/src/emucore/stella.pro @@ -19637,3 +19637,9 @@ "Cartridge.Rarity" "Hack" "Controller.Left" "PADDLES" "" + +"Cartridge.MD5" "45c4413dd703b9cfea49a13709d560eb" +"Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" +"Cartridge.Name" "Challenge of.... Nexar, The (Jone Yuan) (Hack)" +"Cartridge.Note" "Hack" +""