mirror of https://github.com/stella-emu/stella.git
Well, it's finally here. First pass at the new TIA code, which improves
emulation when performing 'illegal' HMOVEs (aka, when modifying the HMxx registers within 24 CPU cycles of HMOVE). All tweaks for illegal HMOVEs have been removed; and all ROMs that previously needed those tweaks are now working correctly. Several other ROMs are fixed as well, including Bumper Bash and Pole Position. As this is WIP, there is also some breakage: 1) Cosmic Ark 'TIA confusion mode' effects aren't complete; the movement is correct, but the missile widths aren't corrected yet. 2) Performing a write to NUSIZx while a player is still drawing isn't complete. This breaks several ROMs that worked before, such as Galaxian and Space Instigators. 3) Writes to RESPx aren't complete yet, especially if they're combined with an immediate write to NUSIZx. Most of the ideas (and some code) for these changes comes from contributions to MESS and EMU7800. Where applicable, permission was obtained from the original author to use the code/ideas. git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@1845 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
c457cea658
commit
5e4b690d8d
|
@ -473,9 +473,9 @@ int Debugger::step()
|
|||
|
||||
int cyc = mySystem->cycles();
|
||||
|
||||
unlockState();
|
||||
unlockBankswitchState();
|
||||
myOSystem->console().tia().updateScanlineByStep();
|
||||
lockState();
|
||||
lockBankswitchState();
|
||||
|
||||
return mySystem->cycles() - cyc;
|
||||
}
|
||||
|
@ -501,9 +501,9 @@ int Debugger::trace()
|
|||
int cyc = mySystem->cycles();
|
||||
int targetPC = myCpuDebug->pc() + 3; // return address
|
||||
|
||||
unlockState();
|
||||
unlockBankswitchState();
|
||||
myOSystem->console().tia().updateScanlineByTrace(targetPC);
|
||||
lockState();
|
||||
lockBankswitchState();
|
||||
|
||||
return mySystem->cycles() - cyc;
|
||||
}
|
||||
|
@ -633,9 +633,13 @@ void Debugger::nextScanline(int lines)
|
|||
{
|
||||
saveOldState();
|
||||
|
||||
unlockState();
|
||||
myTiaOutput->advanceScanline(lines);
|
||||
lockState();
|
||||
unlockBankswitchState();
|
||||
while(lines)
|
||||
{
|
||||
myOSystem->console().tia().updateScanline();
|
||||
--lines;
|
||||
}
|
||||
lockBankswitchState();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -643,9 +647,13 @@ void Debugger::nextFrame(int frames)
|
|||
{
|
||||
saveOldState();
|
||||
|
||||
unlockState();
|
||||
myTiaOutput->advance(frames);
|
||||
lockState();
|
||||
unlockBankswitchState();
|
||||
while(frames)
|
||||
{
|
||||
myOSystem->console().tia().update();
|
||||
--frames;
|
||||
}
|
||||
lockBankswitchState();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -746,14 +754,14 @@ void Debugger::saveOldState()
|
|||
void Debugger::setStartState()
|
||||
{
|
||||
// Lock the bus each time the debugger is entered, so we don't disturb anything
|
||||
lockState();
|
||||
lockBankswitchState();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::setQuitState()
|
||||
{
|
||||
// Bus must be unlocked for normal operation when leaving debugger mode
|
||||
unlockState();
|
||||
unlockBankswitchState();
|
||||
|
||||
// execute one instruction on quit. If we're
|
||||
// sitting at a breakpoint/trap, this will get us past it.
|
||||
|
@ -911,14 +919,14 @@ bool Debugger::saveROM(const string& filename) const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::lockState()
|
||||
void Debugger::lockBankswitchState()
|
||||
{
|
||||
mySystem->lockDataBus();
|
||||
myConsole->cartridge().lockBank();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Debugger::unlockState()
|
||||
void Debugger::unlockBankswitchState()
|
||||
{
|
||||
mySystem->unlockDataBus();
|
||||
myConsole->cartridge().unlockBank();
|
||||
|
|
|
@ -306,8 +306,16 @@ class Debugger : public DialogContainer
|
|||
bool setBank(int bank);
|
||||
bool patchROM(int addr, int value);
|
||||
|
||||
void lockState();
|
||||
void unlockState();
|
||||
/**
|
||||
Normally, accessing RAM or ROM during emulation can possibly trigger
|
||||
bankswitching. However, when we're in the debugger, we'd like to
|
||||
inspect values without actually triggering bankswitches. The
|
||||
read/write state must therefore be locked before accessing values,
|
||||
and unlocked for normal emulation to occur.
|
||||
(takes mediasource into account)
|
||||
*/
|
||||
void lockBankswitchState();
|
||||
void unlockBankswitchState();
|
||||
|
||||
private:
|
||||
/**
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
// $Id$
|
||||
//============================================================================
|
||||
|
||||
//#define NEWTIA
|
||||
|
||||
#include "System.hxx"
|
||||
#include "Debugger.hxx"
|
||||
|
||||
|
@ -617,11 +615,7 @@ uInt8 TIADebug::hmP0(int newVal)
|
|||
if(newVal > -1)
|
||||
mySystem.poke(HMP0, newVal << 4);
|
||||
|
||||
#ifdef NEWTIA
|
||||
return myTIA.myHMP0 >> 4;
|
||||
#else
|
||||
return myTIA.myHMP0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -630,11 +624,7 @@ uInt8 TIADebug::hmP1(int newVal)
|
|||
if(newVal > -1)
|
||||
mySystem.poke(HMP1, newVal << 4);
|
||||
|
||||
#ifdef NEWTIA
|
||||
return myTIA.myHMP1 >> 4;
|
||||
#else
|
||||
return myTIA.myHMP1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -643,11 +633,7 @@ uInt8 TIADebug::hmM0(int newVal)
|
|||
if(newVal > -1)
|
||||
mySystem.poke(HMM0, newVal << 4);
|
||||
|
||||
#ifdef NEWTIA
|
||||
return myTIA.myHMM0 >> 4;
|
||||
#else
|
||||
return myTIA.myHMM0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -656,11 +642,7 @@ uInt8 TIADebug::hmM1(int newVal)
|
|||
if(newVal > -1)
|
||||
mySystem.poke(HMM1, newVal << 4);
|
||||
|
||||
#ifdef NEWTIA
|
||||
return myTIA.myHMM1 >> 4;
|
||||
#else
|
||||
return myTIA.myHMM1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -669,11 +651,7 @@ uInt8 TIADebug::hmBL(int newVal)
|
|||
if(newVal > -1)
|
||||
mySystem.poke(HMBL, newVal << 4);
|
||||
|
||||
#ifdef NEWTIA
|
||||
return myTIA.myHMBL >> 4;
|
||||
#else
|
||||
return myTIA.myHMBL;
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -63,26 +63,6 @@ void TiaOutputWidget::loadConfig()
|
|||
setDirty(); draw();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TiaOutputWidget::advanceScanline(int lines)
|
||||
{
|
||||
while(lines)
|
||||
{
|
||||
instance().console().tia().updateScanline();
|
||||
--lines;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TiaOutputWidget::advance(int frames)
|
||||
{
|
||||
while(frames)
|
||||
{
|
||||
instance().console().tia().update();
|
||||
--frames;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TiaOutputWidget::handleMouseDown(int x, int y, int button, int clickCount)
|
||||
{
|
||||
|
|
|
@ -49,8 +49,6 @@ class TiaOutputWidget : public Widget, public CommandSender
|
|||
virtual bool handleKeyDown(int ascii, int keycode, int modifiers);
|
||||
virtual bool handleKeyUp(int ascii, int keycode, int modifiers);
|
||||
*/
|
||||
void advanceScanline(int lines);
|
||||
void advance(int frames);
|
||||
|
||||
protected:
|
||||
void handleMouseDown(int x, int y, int button, int clickCount);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -266,6 +266,19 @@ class TIA : public Device
|
|||
// Convert resistance from ports to dumped value
|
||||
uInt8 dumpedInputPort(int resistance);
|
||||
|
||||
// Write the specified value to the HMOVE registers at the given clock
|
||||
void pokeHMP0(uInt8 value, Int32 clock);
|
||||
void pokeHMP1(uInt8 value, Int32 clock);
|
||||
void pokeHMM0(uInt8 value, Int32 clock);
|
||||
void pokeHMM1(uInt8 value, Int32 clock);
|
||||
void pokeHMBL(uInt8 value, Int32 clock);
|
||||
|
||||
// Apply motion to registers when HMOVE is currently active
|
||||
inline void applyActiveHMOVEMotion(int hpos, Int16& pos, Int32 motionClock);
|
||||
|
||||
// Apply motion to registers when HMOVE was previously active
|
||||
inline void applyPreviousHMOVEMotion(int hpos, Int16& pos, uInt8 motion);
|
||||
|
||||
private:
|
||||
// Console the TIA is associated with
|
||||
Console& myConsole;
|
||||
|
@ -321,29 +334,11 @@ class TIA : public Device
|
|||
// displayed portion of the frame.
|
||||
Int32 myClocksToEndOfScanLine;
|
||||
|
||||
// The color clocks elapsed so far for each of the graphical objects,
|
||||
// as denoted by 'MOTCK' line described in A. Towers TIA Hardware Notes
|
||||
Int32 myMotionClockP0;
|
||||
Int32 myMotionClockP1;
|
||||
Int32 myMotionClockM0;
|
||||
Int32 myMotionClockM1;
|
||||
Int32 myMotionClockBL;
|
||||
|
||||
// Indicates 'start' signal for each of the graphical objects as
|
||||
// described in A. Towers TIA Hardware Notes
|
||||
Int32 myStartP0;
|
||||
Int32 myStartP1;
|
||||
Int32 myStartM0;
|
||||
Int32 myStartM1;
|
||||
|
||||
// Indicates the total number of scanlines generated by the last frame
|
||||
Int32 myScanlineCountForLastFrame;
|
||||
|
||||
// Indicates the current scanline during a partial frame.
|
||||
Int32 myCurrentScanline;
|
||||
uInt32 myScanlineCountForLastFrame;
|
||||
|
||||
// Indicates the maximum number of scanlines to be generated for a frame
|
||||
Int32 myMaximumNumberOfScanlines;
|
||||
uInt32 myMaximumNumberOfScanlines;
|
||||
|
||||
// Color clock when VSYNC ending causes a new frame to be started
|
||||
Int32 myVSYNCFinishClock;
|
||||
|
@ -377,25 +372,25 @@ class TIA : public Device
|
|||
uInt8 myDGRP1; // Player 1 delayed graphics register
|
||||
|
||||
bool myENAM0; // Indicates if missle 0 is enabled
|
||||
bool myENAM1; // Indicates if missle 0 is enabled
|
||||
bool myENAM1; // Indicates if missle 1 is enabled
|
||||
|
||||
bool myENABL; // Indicates if the ball is enabled
|
||||
bool myDENABL; // Indicates if the virtically delayed ball is enabled
|
||||
bool myDENABL; // Indicates if the vertically delayed ball is enabled
|
||||
|
||||
Int8 myHMP0; // Player 0 horizontal motion register
|
||||
Int8 myHMP1; // Player 1 horizontal motion register
|
||||
Int8 myHMM0; // Missle 0 horizontal motion register
|
||||
Int8 myHMM1; // Missle 1 horizontal motion register
|
||||
Int8 myHMBL; // Ball horizontal motion register
|
||||
uInt8 myHMP0; // Player 0 horizontal motion register
|
||||
uInt8 myHMP1; // Player 1 horizontal motion register
|
||||
uInt8 myHMM0; // Missle 0 horizontal motion register
|
||||
uInt8 myHMM1; // Missle 1 horizontal motion register
|
||||
uInt8 myHMBL; // Ball horizontal motion register
|
||||
|
||||
bool myVDELP0; // Indicates if player 0 is being virtically delayed
|
||||
bool myVDELP1; // Indicates if player 1 is being virtically delayed
|
||||
bool myVDELBL; // Indicates if the ball is being virtically delayed
|
||||
bool myVDELP0; // Indicates if player 0 is being vertically delayed
|
||||
bool myVDELP1; // Indicates if player 1 is being vertically delayed
|
||||
bool myVDELBL; // Indicates if the ball is being vertically delayed
|
||||
|
||||
bool myRESMP0; // Indicates if missle 0 is reset to player 0
|
||||
bool myRESMP1; // Indicates if missle 1 is reset to player 1
|
||||
|
||||
uInt16 myCollision; // Collision register
|
||||
uInt16 myCollision; // Collision register
|
||||
|
||||
// Note that these position registers contain the color clock
|
||||
// on which the object's serial output should begin (0 to 159)
|
||||
|
@ -405,6 +400,29 @@ class TIA : public Device
|
|||
Int16 myPOSM1; // Missle 1 position register
|
||||
Int16 myPOSBL; // Ball position register
|
||||
|
||||
// The color clocks elapsed so far for each of the graphical objects,
|
||||
// as denoted by 'MOTCK' line described in A. Towers TIA Hardware Notes
|
||||
Int32 myMotionClockP0;
|
||||
Int32 myMotionClockP1;
|
||||
Int32 myMotionClockM0;
|
||||
Int32 myMotionClockM1;
|
||||
Int32 myMotionClockBL;
|
||||
|
||||
// Indicates 'start' signal for each of the graphical objects as
|
||||
// described in A. Towers TIA Hardware Notes
|
||||
Int32 myStartP0;
|
||||
Int32 myStartP1;
|
||||
Int32 myStartM0;
|
||||
Int32 myStartM1;
|
||||
|
||||
// Latches for 'more motion required' as described in A. Towers TIA
|
||||
// Hardware Notes
|
||||
bool myHMP0mmr;
|
||||
bool myHMP1mmr;
|
||||
bool myHMM0mmr;
|
||||
bool myHMM1mmr;
|
||||
bool myHMBLmmr;
|
||||
|
||||
// Graphics for Player 0 that should be displayed. This will be
|
||||
// reflected if the player is being reflected.
|
||||
uInt8 myCurrentGRP0;
|
||||
|
@ -435,13 +453,8 @@ class TIA : public Device
|
|||
// Pointer to the currently active mask array for the playfield
|
||||
uInt32* myCurrentPFMask;
|
||||
|
||||
// Audio values. Only used by TIADebug.
|
||||
uInt8 myAUDV0;
|
||||
uInt8 myAUDV1;
|
||||
uInt8 myAUDC0;
|
||||
uInt8 myAUDC1;
|
||||
uInt8 myAUDF0;
|
||||
uInt8 myAUDF1;
|
||||
// Audio values; only used by TIADebug
|
||||
uInt8 myAUDV0, myAUDV1, myAUDC0, myAUDC1, myAUDF0, myAUDF1;
|
||||
|
||||
// Indicates when the dump for paddles was last set
|
||||
Int32 myDumpDisabledCycle;
|
||||
|
@ -449,20 +462,14 @@ class TIA : public Device
|
|||
// Indicates if the dump is current enabled for the paddles
|
||||
bool myDumpEnabled;
|
||||
|
||||
// Color clock when last HMOVE occured
|
||||
Int32 myLastHMOVEClock;
|
||||
|
||||
// Indicates if HMOVE blanks are currently enabled
|
||||
// Indicates if HMOVE blanks are currently or previously enabled,
|
||||
// and at which horizontal position the HMOVE was initiated
|
||||
Int32 myCurrentHMOVEPos;
|
||||
Int32 myPreviousHMOVEPos;
|
||||
bool myHMOVEBlankEnabled;
|
||||
|
||||
// Indicates if unused TIA pins are floating on a peek
|
||||
bool myFloatTIAOutputPins;
|
||||
|
||||
// TIA M0 "bug" used for stars in Cosmic Ark flag
|
||||
bool myM0CosmicArkMotionEnabled;
|
||||
|
||||
// Counter used for TIA M0 "bug"
|
||||
uInt32 myM0CosmicArkCounter;
|
||||
|
||||
// Bitmap of the objects that should be considered while drawing
|
||||
uInt8 myEnabledObjects;
|
||||
|
|
|
@ -550,8 +550,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, 8, 8, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 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,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue