From 453c7fff223aa8a7fc298fc19256b88222a224f6 Mon Sep 17 00:00:00 2001 From: stephena Date: Fri, 15 Jul 2005 18:19:29 +0000 Subject: [PATCH] Second pass at scanline advance. It's still not working, but it's getting closer. I can change a color in the TiwWidget, advance a few scanlines, then do a frame advance. The color changes show up only after advancing the frame, so obviously TIA::update() is doing something that TIA::updateScanline() isn't. Brian, any advice on this one; it seems I don't know as much about the TIA as I thought :( git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@657 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba --- stella/src/debugger/Debugger.cxx | 10 +- stella/src/debugger/TIADebug.cxx | 6 +- stella/src/debugger/TIADebug.hxx | 4 +- stella/src/emucore/FrameBuffer.cxx | 20 ++- stella/src/emucore/FrameBuffer.hxx | 12 +- stella/src/emucore/MediaSrc.hxx | 11 +- stella/src/emucore/TIA.cxx | 207 ++++++++++------------------- stella/src/emucore/TIA.hxx | 14 +- 8 files changed, 129 insertions(+), 155 deletions(-) diff --git a/stella/src/debugger/Debugger.cxx b/stella/src/debugger/Debugger.cxx index 9afefaf9e..8a074ed08 100644 --- a/stella/src/debugger/Debugger.cxx +++ b/stella/src/debugger/Debugger.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: Debugger.cxx,v 1.65 2005-07-15 15:27:29 stephena Exp $ +// $Id: Debugger.cxx,v 1.66 2005-07-15 18:19:28 stephena Exp $ //============================================================================ #include "bspf.hxx" @@ -636,8 +636,12 @@ const string& Debugger::disassemble(int start, int lines) { void Debugger::nextScanline(int lines) { saveOldState(); mySystem->unlockDataBus(); - myTiaDebug->advanceScanline(lines); - myOSystem->frameBuffer().refreshTIA(); +// FIXME - add code to 'darken' the current TIA framebuffer, so we can +// differentiate between old content and newly drawn scanlines +// myTiaDebug->clearTIA(); + + myOSystem->frameBuffer().advanceScanline(lines); + mySystem->lockDataBus(); } diff --git a/stella/src/debugger/TIADebug.cxx b/stella/src/debugger/TIADebug.cxx index 77d6fcd5f..1c3a8db1b 100644 --- a/stella/src/debugger/TIADebug.cxx +++ b/stella/src/debugger/TIADebug.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: TIADebug.cxx,v 1.12 2005-07-15 15:27:29 stephena Exp $ +// $Id: TIADebug.cxx,v 1.13 2005-07-15 18:19:29 stephena Exp $ //============================================================================ #include "System.hxx" @@ -68,9 +68,9 @@ void TIADebug::saveOldState() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIADebug::advanceScanline(int lines) +void TIADebug::clearTIA() { - myTIA->advanceFrameScanline(lines); + myTIA->clearBuffers(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/stella/src/debugger/TIADebug.hxx b/stella/src/debugger/TIADebug.hxx index dc7b363ba..7ceb3cdb9 100644 --- a/stella/src/debugger/TIADebug.hxx +++ b/stella/src/debugger/TIADebug.hxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: TIADebug.hxx,v 1.8 2005-07-15 15:27:29 stephena Exp $ +// $Id: TIADebug.hxx,v 1.9 2005-07-15 18:19:29 stephena Exp $ //============================================================================ #ifndef TIA_DEBUG_HXX @@ -42,7 +42,7 @@ class TIADebug : public DebuggerSystem void saveOldState(); - void advanceScanline(int lines); + void clearTIA(); // FIXME - add whole slew of setXXX() methods uInt8 coluP0(int newVal = -1); diff --git a/stella/src/emucore/FrameBuffer.cxx b/stella/src/emucore/FrameBuffer.cxx index d3f0ca154..88560b49b 100644 --- a/stella/src/emucore/FrameBuffer.cxx +++ b/stella/src/emucore/FrameBuffer.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: FrameBuffer.cxx,v 1.51 2005-07-03 00:53:59 stephena Exp $ +// $Id: FrameBuffer.cxx,v 1.52 2005-07-15 18:19:29 stephena Exp $ //============================================================================ #include @@ -45,6 +45,7 @@ FrameBuffer::FrameBuffer(OSystem* osystem) myPauseStatus(false), theRedrawOverlayIndicator(false), myOverlayRedraws(2), + theScanlineAdvanceIndicator(0), theFrameAdvanceIndicator(0), myMessageTime(0), myMessageText(""), @@ -238,6 +239,12 @@ void FrameBuffer::update() advance = true; --theFrameAdvanceIndicator; } + else if(theScanlineAdvanceIndicator > 0) + { + myOSystem->console().mediaSource().updateScanline(); + advance = true; + --theScanlineAdvanceIndicator; + } // Only update the screen if it's been invalidated or we're in // frame advance mode @@ -294,6 +301,17 @@ void FrameBuffer::refreshOverlay(bool now) if(now) update(); } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void FrameBuffer::advanceScanline(int lines) +{ + if(myOSystem->eventHandler().state() != EventHandler::S_DEBUGGER) + return; + + theScanlineAdvanceIndicator = lines; + while(theScanlineAdvanceIndicator) + update(); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::advance(int frames) { diff --git a/stella/src/emucore/FrameBuffer.hxx b/stella/src/emucore/FrameBuffer.hxx index 36554dec1..bc8c3fc38 100644 --- a/stella/src/emucore/FrameBuffer.hxx +++ b/stella/src/emucore/FrameBuffer.hxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: FrameBuffer.hxx,v 1.46 2005-07-15 15:27:29 stephena Exp $ +// $Id: FrameBuffer.hxx,v 1.47 2005-07-15 18:19:29 stephena Exp $ //============================================================================ #ifndef FRAMEBUFFER_HXX @@ -52,7 +52,7 @@ enum FrameStyle { All GUI elements (ala ScummVM) are drawn here as well. @author Stephen Anthony - @version $Id: FrameBuffer.hxx,v 1.46 2005-07-15 15:27:29 stephena Exp $ + @version $Id: FrameBuffer.hxx,v 1.47 2005-07-15 18:19:29 stephena Exp $ */ class FrameBuffer { @@ -145,6 +145,11 @@ class FrameBuffer */ void refreshOverlay(bool now = false); + /** + Indicates that the emulation should advance given number of scanlines. + */ + void advanceScanline(int lines); + /** Indicates that the emulation should advance given number of frames. */ @@ -459,6 +464,9 @@ class FrameBuffer // Number of times menu have been drawn int myOverlayRedraws; + // Indicates how many scanlines the emulation should advance + int theScanlineAdvanceIndicator; + // Indicates how many frames the emulation should advance int theFrameAdvanceIndicator; diff --git a/stella/src/emucore/MediaSrc.hxx b/stella/src/emucore/MediaSrc.hxx index 8737881a5..dbe56722b 100644 --- a/stella/src/emucore/MediaSrc.hxx +++ b/stella/src/emucore/MediaSrc.hxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: MediaSrc.hxx,v 1.11 2005-06-29 13:11:03 stephena Exp $ +// $Id: MediaSrc.hxx,v 1.12 2005-07-15 18:19:29 stephena Exp $ //============================================================================ #ifndef MEDIASOURCE_HXX @@ -30,7 +30,7 @@ class Sound; This class provides an interface for accessing graphics and audio data. @author Bradford W. Mott - @version $Id: MediaSrc.hxx,v 1.11 2005-06-29 13:11:03 stephena Exp $ + @version $Id: MediaSrc.hxx,v 1.12 2005-07-15 18:19:29 stephena Exp $ */ class MediaSource { @@ -54,6 +54,13 @@ class MediaSource */ virtual void update() = 0; + /** + This method should be called whenever a new scanline is to be drawn. + Invoking this method will update the graphics buffer and generate + the corresponding audio samples. + */ + virtual void updateScanline() = 0; + /** Answers the current frame buffer diff --git a/stella/src/emucore/TIA.cxx b/stella/src/emucore/TIA.cxx index 487b67f22..92d858b80 100644 --- a/stella/src/emucore/TIA.cxx +++ b/stella/src/emucore/TIA.cxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: TIA.cxx,v 1.47 2005-07-15 15:27:29 stephena Exp $ +// $Id: TIA.cxx,v 1.48 2005-07-15 18:19:29 stephena Exp $ //============================================================================ #include @@ -129,10 +129,7 @@ void TIA::reset() mySound->reset(); // Clear frame buffers - for(uInt32 i = 0; i < 160 * 300; ++i) - { - myCurrentFrameBuffer[i] = myPreviousFrameBuffer[i] = 0; - } + clearBuffers(); // Reset pixel pointer and drawing flag myFramePointer = myCurrentFrameBuffer; @@ -548,6 +545,70 @@ void TIA::update() myFrameCounter++; } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void TIA::updateScanline() +{ + // FIXME - extend this method to draw partial scanlines + // ie, when step/trace is called from the debugger + + uInt8* tmp = myCurrentFrameBuffer; + myCurrentFrameBuffer = myPreviousFrameBuffer; + myPreviousFrameBuffer = tmp; + + // Remember the number of clocks which have passed on the current scanline + // so that we can adjust the frame's starting clock by this amount. This + // is necessary since some games position objects during VSYNC and the + // TIA's internal counters are not reset by VSYNC. + uInt32 clocks = ((mySystem->cycles() * 3) - myClockWhenFrameStarted) % 228; + + // Ask the system to reset the cycle count so it doesn't overflow + mySystem->resetCycles(); + + // Setup clocks that'll be used for drawing this frame + myClockWhenFrameStarted = -1 * clocks; + myClockStartDisplay = myClockWhenFrameStarted + myStartDisplayOffset; + myClockStopDisplay = myClockWhenFrameStarted + myStopDisplayOffset; + myClockAtLastUpdate = myClockStartDisplay; + myClocksToEndOfScanLine = 228; + + // Reset frame buffer pointer + myFramePointer = myCurrentFrameBuffer; + + // If color loss is enabled then update the color registers based on + // the number of scanlines in the last frame that was generated + if(myColorLossEnabled) + { + if(myScanlineCountForLastFrame & 0x01) + { + myCOLUP0 |= 0x01010101; + myCOLUP1 |= 0x01010101; + myCOLUPF |= 0x01010101; + myCOLUBK |= 0x01010101; + } + else + { + myCOLUP0 &= 0xfefefefe; + myCOLUP1 &= 0xfefefefe; + myCOLUPF &= 0xfefefefe; + myCOLUBK &= 0xfefefefe; + } + } + + // Execute instructions until scanline is finished + mySystem->m6502().execute(76); + + // TODO: have code here that handles errors.... + + // Compute the number of scanlines in the frame + uInt32 totalClocks = (mySystem->cycles() * 3) - myClockWhenFrameStarted; + myScanlineCountForLastFrame = totalClocks / 228; + +cerr << "myScanlineCountForLastFrame = " << myScanlineCountForLastFrame << endl; + + // Stats counters + myFrameCounter++; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt32* TIA::palette() const { @@ -1809,142 +1870,12 @@ inline void TIA::waitHorizontalSync() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::advanceFrameScanline(int lines) +void TIA::clearBuffers() { - // Ignore # of lines for now -cerr << "TIA::advanceFrameScanline\n"; - - Int32 clock = mySystem->cycles() * 3; - - // See if we're in the nondisplayable portion of the screen or if - // we've already updated this portion of the screen - if((clock < myClockStartDisplay) || - (myClockAtLastUpdate >= myClockStopDisplay) || - (myClockAtLastUpdate >= clock)) + for(uInt32 i = 0; i < 160 * 300; ++i) { - return; + myCurrentFrameBuffer[i] = myPreviousFrameBuffer[i] = 0; } - - // Truncate the number of cycles to update to the stop display point - if(clock > myClockStopDisplay) - { - clock = myClockStopDisplay; - } - - // Update frame one scanline at a time -// do - { - // Compute the number of clocks we're going to update - Int32 clocksToUpdate = 0; - - // Remember how many clocks we are from the left side of the screen - Int32 clocksFromStartOfScanLine = 228 - myClocksToEndOfScanLine; - - // See if we're updating more than the current scanline - if(clock > (myClockAtLastUpdate + myClocksToEndOfScanLine)) - { - // Yes, we have more than one scanline to update so finish current one - clocksToUpdate = myClocksToEndOfScanLine; - myClocksToEndOfScanLine = 228; - myClockAtLastUpdate += clocksToUpdate; - } - else - { - // No, so do as much of the current scanline as possible - clocksToUpdate = clock - myClockAtLastUpdate; - myClocksToEndOfScanLine -= clocksToUpdate; - myClockAtLastUpdate = clock; - } - - Int32 startOfScanLine = HBLANK + myFrameXStart; - - // Skip over as many horizontal blank clocks as we can - if(clocksFromStartOfScanLine < startOfScanLine) - { - uInt32 tmp; - - if((startOfScanLine - clocksFromStartOfScanLine) < clocksToUpdate) - tmp = startOfScanLine - clocksFromStartOfScanLine; - else - tmp = clocksToUpdate; - - clocksFromStartOfScanLine += tmp; - clocksToUpdate -= tmp; - } - - // Remember frame pointer in case HMOVE blanks need to be handled - uInt8* oldFramePointer = myFramePointer; - - // Update as much of the scanline as we can - if(clocksToUpdate != 0) - { - updateFrameScanline(clocksToUpdate, clocksFromStartOfScanLine - HBLANK); - } - - // Handle HMOVE blanks if they are enabled - if(myHMOVEBlankEnabled && (startOfScanLine < HBLANK + 8) && - (clocksFromStartOfScanLine < (HBLANK + 8))) - { - Int32 blanks = (HBLANK + 8) - clocksFromStartOfScanLine; - memset(oldFramePointer, 0, blanks); - - if((clocksToUpdate + clocksFromStartOfScanLine) >= (HBLANK + 8)) - { - myHMOVEBlankEnabled = false; - } - } - - // See if we're at the end of a scanline - if(myClocksToEndOfScanLine == 228) - { - myFramePointer -= (160 - myFrameWidth - myFrameXStart); - - // Yes, so set PF mask based on current CTRLPF reflection state - myCurrentPFMask = ourPlayfieldTable[myCTRLPF & 0x01]; - - // 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). - myCurrentP0Mask = &ourPlayerMaskTable[myPOSP0 & 0x03] - [0][myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFC)]; - myCurrentP1Mask = &ourPlayerMaskTable[myPOSP1 & 0x03] - [0][myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFC)]; - - // Handle the "Cosmic Ark" TIA bug if it's enabled - if(myM0CosmicArkMotionEnabled) - { - // Movement table associated with the bug - static uInt32 m[4] = {18, 33, 0, 17}; - - myM0CosmicArkCounter = (myM0CosmicArkCounter + 1) & 3; - myPOSM0 -= m[myM0CosmicArkCounter]; - - if(myPOSM0 >= 160) - myPOSM0 -= 160; - else if(myPOSM0 < 0) - myPOSM0 += 160; - - if(myM0CosmicArkCounter == 1) - { - // Stretch this missle so it's at least 2 pixels wide - myCurrentM0Mask = &ourMissleMaskTable[myPOSM0 & 0x03] - [myNUSIZ0 & 0x07][((myNUSIZ0 & 0x30) >> 4) | 0x01] - [160 - (myPOSM0 & 0xFC)]; - } - else if(myM0CosmicArkCounter == 2) - { - // Missle is disabled on this line - myCurrentM0Mask = &ourDisabledMaskTable[0]; - } - else - { - myCurrentM0Mask = &ourMissleMaskTable[myPOSM0 & 0x03] - [myNUSIZ0 & 0x07][(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFC)]; - } - } - } - } -// while(myClockAtLastUpdate < clock); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/stella/src/emucore/TIA.hxx b/stella/src/emucore/TIA.hxx index eb2535d4b..ba99e17db 100644 --- a/stella/src/emucore/TIA.hxx +++ b/stella/src/emucore/TIA.hxx @@ -13,7 +13,7 @@ // See the file "license" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // -// $Id: TIA.hxx,v 1.25 2005-07-15 15:27:29 stephena Exp $ +// $Id: TIA.hxx,v 1.26 2005-07-15 18:19:29 stephena Exp $ //============================================================================ #ifndef TIA_HXX @@ -42,7 +42,7 @@ class Settings; be displayed on screen. @author Bradford W. Mott - @version $Id: TIA.hxx,v 1.25 2005-07-15 15:27:29 stephena Exp $ + @version $Id: TIA.hxx,v 1.26 2005-07-15 18:19:29 stephena Exp $ */ class TIA : public Device , public MediaSource { @@ -129,6 +129,12 @@ class TIA : public Device , public MediaSource */ virtual void update(); + /** + This method should be called to update the media source with + a new scanline. + */ + virtual void updateScanline(); + /** Answers the current frame buffer @@ -239,8 +245,8 @@ class TIA : public Device , public MediaSource // Waste cycles until the current scanline is finished void waitHorizontalSync(); - // Draw the specified number of scanlines (for debugger use only) - void advanceFrameScanline(int lines); + // Clear both internal TIA buffers to black (palette color 0) + void clearBuffers(); private: // Console the TIA is associated with