Scaled back some TIA changes from the previous alpha release. The changes

are too invasive to fix right now, and I haven't researched what the
correct route should be.  Basically, Stella doesn't properly emulate the
behaviour of writes to RESxx and NUSIZx while graphics are currently
being drawn.  The tweaks currently present restore functionality to the
2.8.4 release, but are still incorrect in some ROMs (Bumper Bash and Pole
Position).

Reworked 'object disable' mode in the TIA class.  It should now be
slightly faster, and correctly disable objects in all cases
(previously, it was possible for some objects to be enabled depending
on the state of other objects, even when they were specifically
disabled).

Changed NUSIZx descriptors in the debugger to more clearly indicate
what's going on.

Cleaned up TIATable enum's, and eliminated duplication enumerations in
different parts of the codebase.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1855 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2009-08-21 14:29:59 +00:00
parent 339956b144
commit 3006419014
11 changed files with 189 additions and 197 deletions

View File

@ -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).

View File

@ -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";
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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

View File

@ -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");

View File

@ -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

View File

@ -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)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" },

View File

@ -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;
}

View File

@ -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

View File

@ -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];

View File

@ -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];

View File

@ -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"
""