diff --git a/src/emucore/tia/core_6502ts/Background.cxx b/src/emucore/tia/Background.cxx similarity index 100% rename from src/emucore/tia/core_6502ts/Background.cxx rename to src/emucore/tia/Background.cxx diff --git a/src/emucore/tia/core_6502ts/Background.hxx b/src/emucore/tia/Background.hxx similarity index 100% rename from src/emucore/tia/core_6502ts/Background.hxx rename to src/emucore/tia/Background.hxx diff --git a/src/emucore/tia/core_6502ts/Ball.cxx b/src/emucore/tia/Ball.cxx similarity index 100% rename from src/emucore/tia/core_6502ts/Ball.cxx rename to src/emucore/tia/Ball.cxx diff --git a/src/emucore/tia/core_6502ts/Ball.hxx b/src/emucore/tia/Ball.hxx similarity index 100% rename from src/emucore/tia/core_6502ts/Ball.hxx rename to src/emucore/tia/Ball.hxx diff --git a/src/emucore/tia/core_6502ts/DelayQueue.cxx b/src/emucore/tia/DelayQueue.cxx similarity index 100% rename from src/emucore/tia/core_6502ts/DelayQueue.cxx rename to src/emucore/tia/DelayQueue.cxx diff --git a/src/emucore/tia/core_6502ts/DelayQueue.hxx b/src/emucore/tia/DelayQueue.hxx similarity index 100% rename from src/emucore/tia/core_6502ts/DelayQueue.hxx rename to src/emucore/tia/DelayQueue.hxx diff --git a/src/emucore/tia/core_6502ts/DelayQueueMember.cxx b/src/emucore/tia/DelayQueueMember.cxx similarity index 100% rename from src/emucore/tia/core_6502ts/DelayQueueMember.cxx rename to src/emucore/tia/DelayQueueMember.cxx diff --git a/src/emucore/tia/core_6502ts/DelayQueueMember.hxx b/src/emucore/tia/DelayQueueMember.hxx similarity index 100% rename from src/emucore/tia/core_6502ts/DelayQueueMember.hxx rename to src/emucore/tia/DelayQueueMember.hxx diff --git a/src/emucore/tia/core_6502ts/DrawCounterDecodes.cxx b/src/emucore/tia/DrawCounterDecodes.cxx similarity index 100% rename from src/emucore/tia/core_6502ts/DrawCounterDecodes.cxx rename to src/emucore/tia/DrawCounterDecodes.cxx diff --git a/src/emucore/tia/core_6502ts/DrawCounterDecodes.hxx b/src/emucore/tia/DrawCounterDecodes.hxx similarity index 100% rename from src/emucore/tia/core_6502ts/DrawCounterDecodes.hxx rename to src/emucore/tia/DrawCounterDecodes.hxx diff --git a/src/emucore/tia/core_6502ts/FrameManager.cxx b/src/emucore/tia/FrameManager.cxx similarity index 100% rename from src/emucore/tia/core_6502ts/FrameManager.cxx rename to src/emucore/tia/FrameManager.cxx diff --git a/src/emucore/tia/core_6502ts/FrameManager.hxx b/src/emucore/tia/FrameManager.hxx similarity index 100% rename from src/emucore/tia/core_6502ts/FrameManager.hxx rename to src/emucore/tia/FrameManager.hxx diff --git a/src/emucore/tia/core_6502ts/LatchedInput.cxx b/src/emucore/tia/LatchedInput.cxx similarity index 100% rename from src/emucore/tia/core_6502ts/LatchedInput.cxx rename to src/emucore/tia/LatchedInput.cxx diff --git a/src/emucore/tia/core_6502ts/LatchedInput.hxx b/src/emucore/tia/LatchedInput.hxx similarity index 100% rename from src/emucore/tia/core_6502ts/LatchedInput.hxx rename to src/emucore/tia/LatchedInput.hxx diff --git a/src/emucore/tia/core_6502ts/Missile.cxx b/src/emucore/tia/Missile.cxx similarity index 100% rename from src/emucore/tia/core_6502ts/Missile.cxx rename to src/emucore/tia/Missile.cxx diff --git a/src/emucore/tia/core_6502ts/Missile.hxx b/src/emucore/tia/Missile.hxx similarity index 100% rename from src/emucore/tia/core_6502ts/Missile.hxx rename to src/emucore/tia/Missile.hxx diff --git a/src/emucore/tia/core_6502ts/PaddleReader.cxx b/src/emucore/tia/PaddleReader.cxx similarity index 100% rename from src/emucore/tia/core_6502ts/PaddleReader.cxx rename to src/emucore/tia/PaddleReader.cxx diff --git a/src/emucore/tia/core_6502ts/PaddleReader.hxx b/src/emucore/tia/PaddleReader.hxx similarity index 100% rename from src/emucore/tia/core_6502ts/PaddleReader.hxx rename to src/emucore/tia/PaddleReader.hxx diff --git a/src/emucore/tia/core_6502ts/Player.cxx b/src/emucore/tia/Player.cxx similarity index 100% rename from src/emucore/tia/core_6502ts/Player.cxx rename to src/emucore/tia/Player.cxx diff --git a/src/emucore/tia/core_6502ts/Player.hxx b/src/emucore/tia/Player.hxx similarity index 100% rename from src/emucore/tia/core_6502ts/Player.hxx rename to src/emucore/tia/Player.hxx diff --git a/src/emucore/tia/core_6502ts/Playfield.cxx b/src/emucore/tia/Playfield.cxx similarity index 100% rename from src/emucore/tia/core_6502ts/Playfield.cxx rename to src/emucore/tia/Playfield.cxx diff --git a/src/emucore/tia/core_6502ts/Playfield.hxx b/src/emucore/tia/Playfield.hxx similarity index 100% rename from src/emucore/tia/core_6502ts/Playfield.hxx rename to src/emucore/tia/Playfield.hxx diff --git a/src/emucore/tia/core_6502ts/TIA.cxx b/src/emucore/tia/TIA.cxx similarity index 100% rename from src/emucore/tia/core_6502ts/TIA.cxx rename to src/emucore/tia/TIA.cxx diff --git a/src/emucore/tia/core_6502ts/TIA.hxx b/src/emucore/tia/TIA.hxx similarity index 100% rename from src/emucore/tia/core_6502ts/TIA.hxx rename to src/emucore/tia/TIA.hxx diff --git a/src/emucore/tia/core_6502ts/Types.hxx b/src/emucore/tia/Types.hxx similarity index 100% rename from src/emucore/tia/core_6502ts/Types.hxx rename to src/emucore/tia/Types.hxx diff --git a/src/emucore/tia/core_default/TIA.cxx b/src/emucore/tia/core_default/TIA.cxx deleted file mode 100644 index 88e3b5908..000000000 --- a/src/emucore/tia/core_default/TIA.cxx +++ /dev/null @@ -1,2485 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2016 by Bradford W. Mott, Stephen Anthony -// and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// $Id$ -//============================================================================ - -#include "bspf.hxx" - -#ifdef DEBUGGER_SUPPORT - #include "CartDebug.hxx" -#endif - -#include "Console.hxx" -#include "Control.hxx" -#include "Device.hxx" -#include "M6502.hxx" -#include "Settings.hxx" -#include "Sound.hxx" -#include "System.hxx" -#include "TIATables.hxx" - -#include "TIA.hxx" - -#define HBLANK 68 -#define CLAMP_POS(reg) if(reg < 0) { reg += 160; } reg %= 160; - -namespace TIADefaultCore { - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -TIA::TIA(Console& console, Sound& sound, Settings& settings) - : myConsole(console), - mySound(sound), - mySettings(settings), - myFrameYStart(34), - myFrameHeight(210), - myMaximumNumberOfScanlines(262), - myStartScanline(0) -{ - // Allocate buffers for two frame buffers - myCurrentFrameBuffer = make_ptr(160 * 320); - myPreviousFrameBuffer = make_ptr(160 * 320); - - // Compute all of the mask tables - TIATables::computeAllTables(); - - // Set initial state - initialize(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::initialize() -{ - myFramePointer = nullptr; - myFramePointerOffset = myFramePointerClocks = myStopDisplayOffset = 0; - - myClockWhenFrameStarted = myClockStartDisplay = myClockStopDisplay = - myClockAtLastUpdate = myClocksToEndOfScanLine = myVSYNCFinishClock = 0; - - myScanlineCountForLastFrame = myStartScanline = 0; - - myVSYNC = myVBLANK = myNUSIZ0 = myNUSIZ1 = 0; - - myPlayfieldPriorityAndScore = myCTRLPF = 0; - myColor[P0Color] = myColor[P1Color] = myColor[PFColor] = myColor[BKColor] = 0; - myColor[M0Color] = myColor[M1Color] = myColor[BLColor] = myColor[HBLANKColor] = 0; - myColorPtr = nullptr; - - myREFP0 = myREFP1 = false; - myPF = 0; - myGRP0 = myGRP1 = myDGRP0 = myDGRP1 = myCurrentGRP0 = myCurrentGRP1 = 0; - myENAM0 = myENAM1 = myENABL = myDENABL = false; - myHMP0 = myHMP1 = myHMM0 = myHMM1 = myHMBL = 0; - myVDELP0 = myVDELP1 = myVDELBL = myRESMP0 = myRESMP1 = false; - - myCollision = 0; - myCollisionEnabledMask = 0xFFFFFFFF; - myPOSP0 = myPOSP1 = myPOSM0 = myPOSM1 = myPOSBL = 0; - - myMotionClockP0 = myMotionClockP1 = myMotionClockM0 = - myMotionClockM1 = myMotionClockBL = 0; - - myStartP0 = myStartP1 = myStartM0 = myStartM1 = 0; - mySuppressP0 = mySuppressP1 = 0; - myHMP0mmr = myHMP1mmr = myHMM0mmr = myHMM1mmr = myHMBLmmr = false; - - myP0Mask = &TIATables::PxMask[0][0][0]; - myP1Mask = &TIATables::PxMask[0][0][0]; - myM0Mask = &TIATables::MxMask[0][0][0]; - myM1Mask = &TIATables::MxMask[0][0][0]; - myBLMask = &TIATables::BLMask[0][0]; - myPFMask = TIATables::PFMask[0]; - - myAUDV0 = myAUDV1 = myAUDF0 = myAUDF1 = myAUDC0 = myAUDC1 = 0; - - myDumpEnabled = false; - myDumpDisabledCycle = 0; - myINPT4 = myINPT5 = 0x80; - - myCurrentHMOVEPos = myPreviousHMOVEPos = 0x7FFFFFFF; - myHMOVEBlankEnabled = false; - - myTIAPinsDriven = mySettings.getBool("tiadriven"); - - myEnabledObjects = 0; - myDisabledObjects = 0xFF; - - myColorLossEnabled = myPartialFrameFlag = myAutoFrameEnabled = false; - - myFrameCounter = myPALFrameCounter = 0; - myFramerate = 60.0; - - myBitsEnabled = myCollisionsEnabled = true; - myJitterEnabled = mySettings.getBool("tv.jitter"); - myJitterRecoveryFactor = mySettings.getInt("tv.jitter_recovery"); - myNextFrameJitter = myCurrentFrameJitter = myJitterRecovery = 0; - - // Make sure all TIA bits are enabled - enableBits(true); - - // Turn off debug colours (this also sets up the PriorityEncoder) - toggleFixedColors(0); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::reset() -{ - initialize(); // Set initial state - mySound.reset(); // Reset the sound device - frameReset(); // Recalculate the size of the display -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::frameReset() -{ - // Clear frame buffers - clearBuffers(); - - // Reset pixel pointer and drawing flag - myFramePointer = myCurrentFrameBuffer.get(); - - // Calculate color clock offsets for starting and stopping frame drawing - // Note that although we always start drawing at scanline zero, the - // framebuffer that is exposed outside the class actually starts at 'ystart' - myFramePointerOffset = 160 * myFrameYStart; - - myAutoFrameEnabled = (mySettings.getInt("framerate") <= 0); - myFramerate = myConsole.getFramerate(); - - if(myFramerate > 55.0) // NTSC - { - myFixedColor[P0Color] = 0x30; - myFixedColor[P1Color] = 0x16; - myFixedColor[M0Color] = 0x38; - myFixedColor[M1Color] = 0x12; - myFixedColor[BLColor] = 0x7e; - myFixedColor[PFColor] = 0x76; - myFixedColor[BKColor] = 0x0a; - myFixedColor[HBLANKColor] = 0x0e; - myColorLossEnabled = false; - myMaximumNumberOfScanlines = 290; - } - else - { - myFixedColor[P0Color] = 0x62; - myFixedColor[P1Color] = 0x26; - myFixedColor[M0Color] = 0x68; - myFixedColor[M1Color] = 0x2e; - myFixedColor[BLColor] = 0xde; - myFixedColor[PFColor] = 0xd8; - myFixedColor[BKColor] = 0x1c; - myFixedColor[HBLANKColor] = 0x0e; - myColorLossEnabled = mySettings.getBool("colorloss"); - myMaximumNumberOfScanlines = 342; - } - - // NTSC screens will process at least 262 scanlines, - // while PAL will have at least 312 - // In any event, at most 320 lines can be processed - uInt32 scanlines = myFrameYStart + myFrameHeight; - if(myMaximumNumberOfScanlines == 290) - scanlines = std::max(scanlines, 262u); // NTSC - else - scanlines = std::max(scanlines, 312u); // PAL - myStopDisplayOffset = 228 * std::min(scanlines, 320u); - - // Reasonable values to start and stop the current frame drawing - myClockWhenFrameStarted = mySystem->cycles() * 3; - myClockStartDisplay = myClockWhenFrameStarted; - myClockStopDisplay = myClockWhenFrameStarted + myStopDisplayOffset; - myClockAtLastUpdate = myClockWhenFrameStarted; - myClocksToEndOfScanLine = 228; - myVSYNCFinishClock = 0x7FFFFFFF; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::systemCyclesReset() -{ - // Get the current system cycle - uInt32 cycles = mySystem->cycles(); - - // Adjust the sound cycle indicator - mySound.adjustCycleCounter(-1 * cycles); - - // Adjust the dump cycle - myDumpDisabledCycle -= cycles; - - // Get the current color clock the system is using - uInt32 clocks = cycles * 3; - - // Adjust the clocks by this amount since we're reseting the clock to zero - myClockWhenFrameStarted -= clocks; - myClockStartDisplay -= clocks; - myClockStopDisplay -= clocks; - myClockAtLastUpdate -= clocks; - myVSYNCFinishClock -= clocks; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::install(System& system) -{ - installDelegate(system, *this); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::installDelegate(System& system, Device& device) -{ - // Remember which system I'm installed in - mySystem = &system; - - // All accesses are to the given device - System::PageAccess access(&device, System::PA_READWRITE); - - // We're installing in a 2600 system - for(uInt32 i = 0; i < 8192; i += (1 << System::PAGE_SHIFT)) - if((i & 0x1080) == 0x0000) - mySystem->setPageAccess(i >> System::PAGE_SHIFT, access); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool TIA::save(Serializer& out) const -{ - const string& device = name(); - - try - { - out.putString(device); - - out.putInt(myClockWhenFrameStarted); - out.putInt(myClockStartDisplay); - out.putInt(myClockStopDisplay); - out.putInt(myClockAtLastUpdate); - out.putInt(myClocksToEndOfScanLine); - out.putInt(myScanlineCountForLastFrame); - out.putInt(myVSYNCFinishClock); - - out.putByte(myEnabledObjects); - out.putByte(myDisabledObjects); - - out.putByte(myVSYNC); - out.putByte(myVBLANK); - out.putByte(myNUSIZ0); - out.putByte(myNUSIZ1); - - out.putByteArray(myColor, 8); - - out.putByte(myCTRLPF); - out.putByte(myPlayfieldPriorityAndScore); - out.putBool(myREFP0); - out.putBool(myREFP1); - out.putInt(myPF); - out.putByte(myGRP0); - out.putByte(myGRP1); - out.putByte(myDGRP0); - out.putByte(myDGRP1); - out.putBool(myENAM0); - out.putBool(myENAM1); - out.putBool(myENABL); - out.putBool(myDENABL); - out.putByte(myHMP0); - out.putByte(myHMP1); - out.putByte(myHMM0); - out.putByte(myHMM1); - out.putByte(myHMBL); - out.putBool(myVDELP0); - out.putBool(myVDELP1); - out.putBool(myVDELBL); - out.putBool(myRESMP0); - out.putBool(myRESMP1); - out.putShort(myCollision); - out.putInt(myCollisionEnabledMask); - out.putByte(myCurrentGRP0); - out.putByte(myCurrentGRP1); - - out.putBool(myDumpEnabled); - out.putInt(myDumpDisabledCycle); - - out.putShort(myPOSP0); - out.putShort(myPOSP1); - out.putShort(myPOSM0); - out.putShort(myPOSM1); - out.putShort(myPOSBL); - - out.putInt(myMotionClockP0); - out.putInt(myMotionClockP1); - out.putInt(myMotionClockM0); - 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); - out.putBool(myHMM1mmr); - out.putBool(myHMBLmmr); - - out.putInt(myCurrentHMOVEPos); - out.putInt(myPreviousHMOVEPos); - out.putBool(myHMOVEBlankEnabled); - - out.putInt(myFrameCounter); - out.putInt(myPALFrameCounter); - - // Save the sound sample stuff ... - mySound.save(out); - } - catch(...) - { - cerr << "ERROR: TIA::save" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool TIA::load(Serializer& in) -{ - const string& device = name(); - - try - { - if(in.getString() != device) - return false; - - myClockWhenFrameStarted = in.getInt(); - myClockStartDisplay = in.getInt(); - myClockStopDisplay = in.getInt(); - myClockAtLastUpdate = in.getInt(); - myClocksToEndOfScanLine = in.getInt(); - myScanlineCountForLastFrame = in.getInt(); - myVSYNCFinishClock = in.getInt(); - - myEnabledObjects = in.getByte(); - myDisabledObjects = in.getByte(); - - myVSYNC = in.getByte(); - myVBLANK = in.getByte(); - myNUSIZ0 = in.getByte(); - myNUSIZ1 = in.getByte(); - - in.getByteArray(myColor, 8); - - myCTRLPF = in.getByte(); - myPlayfieldPriorityAndScore = in.getByte(); - myREFP0 = in.getBool(); - myREFP1 = in.getBool(); - myPF = in.getInt(); - myGRP0 = in.getByte(); - myGRP1 = in.getByte(); - myDGRP0 = in.getByte(); - myDGRP1 = in.getByte(); - myENAM0 = in.getBool(); - myENAM1 = in.getBool(); - myENABL = in.getBool(); - myDENABL = in.getBool(); - myHMP0 = in.getByte(); - myHMP1 = in.getByte(); - myHMM0 = in.getByte(); - myHMM1 = in.getByte(); - myHMBL = in.getByte(); - myVDELP0 = in.getBool(); - myVDELP1 = in.getBool(); - myVDELBL = in.getBool(); - myRESMP0 = in.getBool(); - myRESMP1 = in.getBool(); - myCollision = in.getShort(); - myCollisionEnabledMask = in.getInt(); - myCurrentGRP0 = in.getByte(); - myCurrentGRP1 = in.getByte(); - - myDumpEnabled = in.getBool(); - myDumpDisabledCycle = in.getInt(); - - myPOSP0 = in.getShort(); - myPOSP1 = in.getShort(); - myPOSM0 = in.getShort(); - myPOSM1 = in.getShort(); - myPOSBL = in.getShort(); - - myMotionClockP0 = in.getInt(); - myMotionClockP1 = in.getInt(); - myMotionClockM0 = in.getInt(); - myMotionClockM1 = in.getInt(); - myMotionClockBL = in.getInt(); - - myStartP0 = in.getInt(); - myStartP1 = in.getInt(); - myStartM0 = in.getInt(); - myStartM1 = in.getInt(); - - mySuppressP0 = in.getByte(); - mySuppressP1 = in.getByte(); - - myHMP0mmr = in.getBool(); - myHMP1mmr = in.getBool(); - myHMM0mmr = in.getBool(); - myHMM1mmr = in.getBool(); - myHMBLmmr = in.getBool(); - - myCurrentHMOVEPos = in.getInt(); - myPreviousHMOVEPos = in.getInt(); - myHMOVEBlankEnabled = in.getBool(); - - myFrameCounter = in.getInt(); - myPALFrameCounter = in.getInt(); - - // Load the sound sample stuff ... - mySound.load(in); - - // Reset TIA bits to be on - enableBits(true); - toggleFixedColors(0); - } - catch(...) - { - cerr << "ERROR: TIA::load" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool TIA::saveDisplay(Serializer& out) const -{ - try - { - out.putBool(myPartialFrameFlag); - out.putInt(myFramePointerClocks); - out.putByteArray(myCurrentFrameBuffer.get(), 160*320); - } - catch(...) - { - cerr << "ERROR: TIA::saveDisplay" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool TIA::loadDisplay(Serializer& in) -{ - try - { - myPartialFrameFlag = in.getBool(); - myFramePointerClocks = in.getInt(); - - // Reset frame buffer pointer and data - clearBuffers(); - myFramePointer = myCurrentFrameBuffer.get(); - in.getByteArray(myCurrentFrameBuffer.get(), 160*320); - memcpy(myPreviousFrameBuffer.get(), myCurrentFrameBuffer.get(), 160*320); - - // If we're in partial frame mode, make sure to re-create the screen - // as it existed when the state was saved - if(myPartialFrameFlag) - myFramePointer += myFramePointerClocks; - } - catch(...) - { - cerr << "ERROR: TIA::loadDisplay" << endl; - return false; - } - - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::update() -{ - // if we've finished a frame, start a new one - if(!myPartialFrameFlag) - startFrame(); - - // Partial frame flag starts out true here. When then 6502 strobes VSYNC, - // TIA::poke() will set this flag to false, so we'll know whether the - // frame got finished or interrupted by the debugger hitting a break/trap. - myPartialFrameFlag = true; - - // Execute instructions until frame is finished, or a breakpoint/trap hits - mySystem->m6502().execute(25000); - - // TODO: have code here that handles errors.... - - endFrame(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline void TIA::startFrame() -{ - // This stuff should only happen at the beginning of a new frame. - myCurrentFrameBuffer.swap(myPreviousFrameBuffer); - - // 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; - myClockStopDisplay = myClockWhenFrameStarted + myStopDisplayOffset; - myClockAtLastUpdate = myClockStartDisplay; - myClocksToEndOfScanLine = 228; - - // Reset frame buffer pointer - myFramePointer = myCurrentFrameBuffer.get(); - myFramePointerClocks = 0; - - // 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) - { - myColor[P0Color] |= 0x01; - myColor[P1Color] |= 0x01; - myColor[PFColor] |= 0x01; - myColor[BKColor] |= 0x01; - myColor[M0Color] |= 0x01; - myColor[M1Color] |= 0x01; - myColor[BLColor] |= 0x01; - } - else - { - myColor[P0Color] &= 0xfe; - myColor[P1Color] &= 0xfe; - myColor[PFColor] &= 0xfe; - myColor[BKColor] &= 0xfe; - myColor[M0Color] &= 0xfe; - myColor[M1Color] &= 0xfe; - myColor[BLColor] &= 0xfe; - } - } - myStartScanline = 0; - - // Stats counters - myFrameCounter++; - if(myScanlineCountForLastFrame >= 287) - myPALFrameCounter++; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline void TIA::endFrame() -{ - uInt32 currentlines = scanlines(); - - // The TIA may generate frames that are 'invisible' to TV (they complete - // before the first visible scanline) - // Such 'short' frames can't simply be eliminated, since they're running - // code at that point; however, they are not shown at all, otherwise the - // double-buffering of the video output will get confused - if(currentlines <= myStartScanline) - { - // Skip display of this frame, as if it wasn't generated at all - startFrame(); - myFrameCounter--; // This frame doesn't contribute to frame count - return; - } - - // Compute the number of scanlines in the frame - uInt32 previousCount = myScanlineCountForLastFrame; - myScanlineCountForLastFrame = currentlines; - - // The following handle cases where scanlines either go too high or too - // low compared to the previous frame, in which case certain portions - // of the framebuffer are cleared to zero (black pixels) - // Due to the FrameBuffer class (potentially) doing dirty-rectangle - // updates, each internal buffer must be set slightly differently, - // otherwise they won't know anything has changed - // Hence, the front buffer is set to pixel 0, and the back to pixel 1 - - // Did we generate too many scanlines? - // (usually caused by VBLANK/VSYNC taking too long or not occurring at all) - // If so, blank entire viewable area - if(myScanlineCountForLastFrame > myMaximumNumberOfScanlines+1) - { - myScanlineCountForLastFrame = myMaximumNumberOfScanlines; - if(previousCount < myMaximumNumberOfScanlines) - { - memset(myCurrentFrameBuffer.get(), 0, 160 * 320); - memset(myPreviousFrameBuffer.get(), 1, 160 * 320); - } - } - // Did the number of scanlines decrease? - // If so, blank scanlines that weren't rendered this frame - else if(myScanlineCountForLastFrame < previousCount && - myScanlineCountForLastFrame < 320 && previousCount < 320) - { - uInt32 offset = myScanlineCountForLastFrame * 160, - stride = (previousCount - myScanlineCountForLastFrame) * 160; - memset(myCurrentFrameBuffer.get() + offset, 0, stride); - memset(myPreviousFrameBuffer.get() + offset, 1, stride); - } - - // Account for frame jitter, skipping the first few frames - if(myJitterEnabled && myFrameCounter > 3) - { - // Set the jitter amount for the current frame - myCurrentFrameJitter = (myNextFrameJitter + myJitterRecovery * - myJitterRecoveryFactor) * 160; - - if(myJitterRecovery < 0) myJitterRecovery++; - else if (myJitterRecovery > 0) myJitterRecovery--; - - // Calculate the jitter amount for the next frame. - // Jitter amount of a frame depends upon the difference - // between the scanline counts of the prior two frames. - myNextFrameJitter = myScanlineCountForLastFrame - previousCount; - - if(myNextFrameJitter < -1) - { - if(myNextFrameJitter / myJitterRecoveryFactor < myJitterRecovery) - { - myJitterRecovery = myNextFrameJitter / myJitterRecoveryFactor; - myNextFrameJitter = 0; - - // Make sure currentFrameBuffer() doesn't return a pointer that - // results in memory being accessed outside of the 160*320 bytes - // allocated for the frame buffer - if(myJitterRecovery * myJitterRecoveryFactor < -Int32(myFrameYStart)) - myJitterRecovery = myFrameYStart / myJitterRecoveryFactor; - } - else - { - myNextFrameJitter = (myNextFrameJitter-1) / 2; - - // Make sure currentFrameBuffer() doesn't return a pointer that - // results in memory being accessed outside of the 160*320 bytes - // allocated for the frame buffer - if(myNextFrameJitter + myJitterRecovery * myJitterRecoveryFactor < - -Int32(myFrameYStart)) - myNextFrameJitter = myFrameYStart; - } - } - else if(myNextFrameJitter > 1) - { - if (myNextFrameJitter / myJitterRecoveryFactor > myJitterRecovery) - { - myJitterRecovery = myNextFrameJitter / myJitterRecoveryFactor; - myNextFrameJitter = 0; - - // Make sure currentFrameBuffer() doesn't return a pointer that - // results in memory being accessed outside of the 160*320 bytes - // allocated for the frame buffer - if(myJitterRecovery * myJitterRecoveryFactor > - 320 - Int32(myFrameYStart) - Int32(myFrameHeight)) - myJitterRecovery = (320 - myFrameYStart - myFrameHeight) / - myJitterRecoveryFactor; - } - else - { - myNextFrameJitter = (myNextFrameJitter+1) / 2; - - // Make sure currentFrameBuffer() doesn't return a pointer that - // results in memory being accessed outside of the 160*320 bytes - // allocated for the frame buffer - if(myNextFrameJitter + myJitterRecovery * myJitterRecoveryFactor > - 320 - Int32(myFrameYStart) - Int32(myFrameHeight)) - myNextFrameJitter = 320 - myFrameYStart - myFrameHeight; - } - } - else - myNextFrameJitter = 0; - } - - // Recalculate framerate. attempting to auto-correct for scanline 'jumps' - if(myAutoFrameEnabled) - { - myFramerate = (myScanlineCountForLastFrame > 285 ? 15600.0 : 15720.0) / - myScanlineCountForLastFrame; - myConsole.setFramerate(myFramerate); - - // Adjust end-of-frame pointer - // We always accommodate the highest # of scanlines, up to the maximum - // size of the buffer (currently, 320 lines) - uInt32 offset = 228 * myScanlineCountForLastFrame; - if(offset > myStopDisplayOffset && offset < 228 * 320) - myStopDisplayOffset = offset; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool TIA::scanlinePos(uInt16& x, uInt16& y) const -{ - if(myPartialFrameFlag) - { - // We only care about the scanline position when it's in the viewable area - if(myFramePointerClocks >= myFramePointerOffset) - { - x = (myFramePointerClocks - myFramePointerOffset) % 160; - y = (myFramePointerClocks - myFramePointerOffset) / 160; - return true; - } - else - { - x = 0; - y = 0; - return false; - } - } - else - { - x = width(); - y = height(); - return false; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::enableBits(bool mode) -{ - toggleBit(P0Bit, mode ? 1 : 0); - toggleBit(P1Bit, mode ? 1 : 0); - toggleBit(M0Bit, mode ? 1 : 0); - toggleBit(M1Bit, mode ? 1 : 0); - toggleBit(BLBit, mode ? 1 : 0); - toggleBit(PFBit, mode ? 1 : 0); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool TIA::toggleBit(TIABit b, uInt8 mode) -{ - // If mode is 0 or 1, use it as a boolean (off or on) - // Otherwise, flip the state - bool on = (mode == 0 || mode == 1) ? bool(mode) : !(myDisabledObjects & b); - if(on) myDisabledObjects |= b; - else myDisabledObjects &= ~b; - - return on; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool TIA::toggleBits() -{ - myBitsEnabled = !myBitsEnabled; - enableBits(myBitsEnabled); - return myBitsEnabled; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::enableCollisions(bool mode) -{ - toggleCollision(P0Bit, mode ? 1 : 0); - toggleCollision(P1Bit, mode ? 1 : 0); - toggleCollision(M0Bit, mode ? 1 : 0); - toggleCollision(M1Bit, mode ? 1 : 0); - toggleCollision(BLBit, mode ? 1 : 0); - toggleCollision(PFBit, mode ? 1 : 0); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool TIA::toggleCollision(TIABit b, uInt8 mode) -{ - uInt16 enabled = myCollisionEnabledMask >> 16; - - // If mode is 0 or 1, use it as a boolean (off or on) - // Otherwise, flip the state - bool on = (mode == 0 || mode == 1) ? bool(mode) : !(enabled & b); - if(on) enabled |= b; - else enabled &= ~b; - - // Assume all collisions are on, then selectively turn the desired ones off - uInt16 mask = 0xffff; - if(!(enabled & P0Bit)) mask &= ~(Cx_M0P0 | Cx_M1P0 | Cx_P0PF | Cx_P0BL | Cx_P0P1); - if(!(enabled & P1Bit)) mask &= ~(Cx_M0P1 | Cx_M1P1 | Cx_P1PF | Cx_P1BL | Cx_P0P1); - if(!(enabled & M0Bit)) mask &= ~(Cx_M0P0 | Cx_M0P1 | Cx_M0PF | Cx_M0BL | Cx_M0M1); - if(!(enabled & M1Bit)) mask &= ~(Cx_M1P0 | Cx_M1P1 | Cx_M1PF | Cx_M1BL | Cx_M0M1); - if(!(enabled & BLBit)) mask &= ~(Cx_P0BL | Cx_P1BL | Cx_M0BL | Cx_M1BL | Cx_BLPF); - if(!(enabled & PFBit)) mask &= ~(Cx_P0PF | Cx_P1PF | Cx_M0PF | Cx_M1PF | Cx_BLPF); - - // Now combine the masks - myCollisionEnabledMask = (enabled << 16) | mask; - - return on; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool TIA::toggleCollisions() -{ - myCollisionsEnabled = !myCollisionsEnabled; - enableCollisions(myCollisionsEnabled); - return myCollisionsEnabled; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool TIA::toggleFixedColors(uInt8 mode) -{ - // If mode is 0 or 1, use it as a boolean (off or on) - // Otherwise, flip the state - bool on = (mode == 0 || mode == 1) ? bool(mode) : - (myColorPtr == myColor ? true : false); - if(on) myColorPtr = myFixedColor; - else myColorPtr = myColor; - - // Set PriorityEncoder - // This needs to be done here, since toggling debug colours also changes - // how colours are interpreted in PF 'score' mode - for(uInt16 x = 0; x < 2; ++x) - { - for(uInt16 enabled = 0; enabled < 256; ++enabled) - { - uInt8 color = BKColor; - if(enabled & PriorityBit) - { - // NOTE: Playfield has priority so ScoreBit isn't used - // Priority from highest to lowest: CTRLPF D2=1, D1=ignored - // PF/BL => P0/M0 => P1/M1 => BK - if((enabled & M1Bit) != 0) color = M1Color; - if((enabled & P1Bit) != 0) color = P1Color; - if((enabled & M0Bit) != 0) color = M0Color; - if((enabled & P0Bit) != 0) color = P0Color; - if((enabled & BLBit) != 0) color = BLColor; - if((enabled & PFBit) != 0) color = PFColor; - } - else - { - if(enabled & ScoreBit) // CTRLPF D2=0, D1=1 - { - if(x == 0) // Score mode left half - { - // Priority from highest to lowest: - // PF/P0/M0 => P1/M1 => BL => BK - if((enabled & BLBit) != 0) color = BLColor; - if((enabled & M1Bit) != 0) color = M1Color; - if((enabled & P1Bit) != 0) color = P1Color; - if((enabled & M0Bit) != 0) color = M0Color; - if((enabled & P0Bit) != 0) color = P0Color; - if((enabled & PFBit) != 0) color = !on ? P0Color : PFColor; - } - else // Score mode right half - { - // Priority from highest to lowest: - // P0/M0 => PF/P1/M1 => BL => BK - if((enabled & BLBit) != 0) color = BLColor; - if((enabled & M1Bit) != 0) color = M1Color; - if((enabled & P1Bit) != 0) color = P1Color; - if((enabled & PFBit) != 0) color = !on ? P1Color : PFColor; - if((enabled & M0Bit) != 0) color = M0Color; - if((enabled & P0Bit) != 0) color = P0Color; - } - } - else - { - // Priority from highest to lowest: CTRLPF D2=0, D1=0 - // P0/M0 => P1/M1 => PF/BL => BK - if((enabled & BLBit) != 0) color = BLColor; - if((enabled & PFBit) != 0) color = PFColor; - if((enabled & M1Bit) != 0) color = M1Color; - if((enabled & P1Bit) != 0) color = P1Color; - if((enabled & M0Bit) != 0) color = M0Color; - if((enabled & P0Bit) != 0) color = P0Color; - } - } - myPriorityEncoder[x][enabled] = color; - } - } - - return on; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool TIA::driveUnusedPinsRandom(uInt8 mode) -{ - // If mode is 0 or 1, use it as a boolean (off or on) - // Otherwise, return the state - if(mode == 0 || mode == 1) - { - myTIAPinsDriven = bool(mode); - mySettings.setValue("tiadriven", myTIAPinsDriven); - } - return myTIAPinsDriven; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool TIA::toggleJitter(uInt8 mode) -{ - // If mode is 0 or 1, use it as a boolean (off or on) - // Otherwise, flip the state - bool on = (mode == 0 || mode == 1) ? bool(mode) : - myJitterEnabled = !myJitterEnabled; - myJitterEnabled = on; - mySettings.setValue("tv.jitter", myJitterEnabled); - - return myJitterEnabled; -} - -#ifdef DEBUGGER_SUPPORT -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::updateScanline() -{ - // Start a new frame if the old one was finished - if(!myPartialFrameFlag) - startFrame(); - - myPartialFrameFlag = true; // true either way - - int totalClocks = (mySystem->cycles() * 3) - myClockWhenFrameStarted; - int endClock = ((totalClocks + 228) / 228) * 228; - - int clock; - do { - mySystem->m6502().execute(1); - clock = mySystem->cycles() * 3; - updateFrame(clock); - } while(clock < endClock); - - // if we finished the frame, get ready for the next one - if(!myPartialFrameFlag) - endFrame(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::updateScanlineByStep() -{ - // Start a new frame if the old one was finished - if(!myPartialFrameFlag) - startFrame(); - - // true either way: - myPartialFrameFlag = true; - - // Update frame by one CPU instruction/color clock - mySystem->m6502().execute(1); - updateFrame(mySystem->cycles() * 3); - - // if we finished the frame, get ready for the next one - if(!myPartialFrameFlag) - endFrame(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::updateScanlineByTrace(int target) -{ - // Start a new frame if the old one was finished - if(!myPartialFrameFlag) - startFrame(); - - // true either way: - myPartialFrameFlag = true; - - while(mySystem->m6502().getPC() != target) - { - mySystem->m6502().execute(1); - updateFrame(mySystem->cycles() * 3); - } - - // if we finished the frame, get ready for the next one - if(!myPartialFrameFlag) - endFrame(); -} -#endif - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::updateFrame(Int32 clock) -{ - // See if we've already updated this portion of the screen - if((clock < myClockStartDisplay) || - (myClockAtLastUpdate >= myClockStopDisplay) || - (myClockAtLastUpdate >= clock)) - return; - - // Truncate the number of cycles to update to the stop display point - if(clock > myClockStopDisplay) - clock = myClockStopDisplay; - - // Determine how many scanlines to process - // It's easier to think about this in scanlines rather than color clocks - uInt32 startLine = (myClockAtLastUpdate - myClockWhenFrameStarted) / 228; - uInt32 endLine = (clock - myClockWhenFrameStarted) / 228; - - // Update frame one scanline at a time - for(uInt32 line = startLine; line <= endLine; ++line) - { - // Only check for inter-line changes after the current scanline - // The ideas for much of the following code was inspired by MESS - // (used with permission from Wilbert Pol) - if(line != startLine) - { - // We're no longer concerned with previously issued HMOVE's - myPreviousHMOVEPos = 0x7FFFFFFF; - bool posChanged = false; - - // Apply pending motion clocks from a HMOVE initiated during the scanline - if(myCurrentHMOVEPos != 0x7FFFFFFF) - { - if(myCurrentHMOVEPos >= 97 && myCurrentHMOVEPos < 157) - { - myPOSP0 -= myMotionClockP0; if(myPOSP0 < 0) myPOSP0 += 160; - myPOSP1 -= myMotionClockP1; if(myPOSP1 < 0) myPOSP1 += 160; - myPOSM0 -= myMotionClockM0; if(myPOSM0 < 0) myPOSM0 += 160; - myPOSM1 -= myMotionClockM1; if(myPOSM1 < 0) myPOSM1 += 160; - myPOSBL -= myMotionClockBL; if(myPOSBL < 0) myPOSBL += 160; - - myPreviousHMOVEPos = myCurrentHMOVEPos; - } - // Indicate that the HMOVE has been completed - myCurrentHMOVEPos = 0x7FFFFFFF; - posChanged = true; - } - - // Apply extra clocks for 'more motion required/mmr' - if(myHMP0mmr) { myPOSP0 -= 17; if(myPOSP0 < 0) myPOSP0 += 160; posChanged = true; } - if(myHMP1mmr) { myPOSP1 -= 17; if(myPOSP1 < 0) myPOSP1 += 160; posChanged = true; } - if(myHMM0mmr) { myPOSM0 -= 17; if(myPOSM0 < 0) myPOSM0 += 160; posChanged = true; } - if(myHMM1mmr) { myPOSM1 -= 17; if(myPOSM1 < 0) myPOSM1 += 160; posChanged = true; } - if(myHMBLmmr) { myPOSBL -= 17; if(myPOSBL < 0) myPOSBL += 160; posChanged = true; } - - // Scanline change, so reset PF mask based on current CTRLPF reflection state - myPFMask = TIATables::PFMask[myCTRLPF & 0x01]; - - // TODO - handle changes to player timing - if(posChanged) - { - } - } - - // 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; - - // 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) - { - // Calculate the ending frame pointer value - uInt8* ending = myFramePointer + clocksToUpdate; - myFramePointerClocks += clocksToUpdate; - - // See if we're in the vertical blank region - if(myVBLANK & 0x02) - { - memset(myFramePointer, 0, clocksToUpdate); - } - // Handle all other possible combinations - else - { - // Update masks - myP0Mask = &TIATables::PxMask[mySuppressP0] - [myNUSIZ0 & 0x07][160 - (myPOSP0 & 0xFF)]; - myP1Mask = &TIATables::PxMask[mySuppressP1] - [myNUSIZ1 & 0x07][160 - (myPOSP1 & 0xFF)]; - myBLMask = &TIATables::BLMask[(myCTRLPF & 0x30) >> 4] - [160 - (myPOSBL & 0xFF)]; - - // TODO - 08-27-2009: Simulate the weird effects of Cosmic Ark and - // Stay Frosty. The movement itself is well understood, but there - // also seems to be some widening and blanking occurring as well. - // This doesn't properly emulate the effect at a low level; it only - // simulates the behaviour as visually seen in the aforementioned - // ROMs. Other ROMs may break this simulation; more testing is - // required to figure out what's really going on here. - if(myHMM0mmr) - { - switch(myPOSM0 % 4) - { - case 3: - // Stretch this missle so it's 2 pixels wide and shifted one - // pixel to the left - myM0Mask = &TIATables::MxMask[myNUSIZ0 & 0x07] - [((myNUSIZ0 & 0x30) >> 4)|1][160 - ((myPOSM0-1) & 0xFF)]; - break; - case 2: - // Missle is disabled on this line - myM0Mask = &TIATables::DisabledMask[0]; - break; - default: - myM0Mask = &TIATables::MxMask[myNUSIZ0 & 0x07] - [(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFF)]; - break; - } - } - else - myM0Mask = &TIATables::MxMask[myNUSIZ0 & 0x07] - [(myNUSIZ0 & 0x30) >> 4][160 - (myPOSM0 & 0xFF)]; - if(myHMM1mmr) - { - switch(myPOSM1 % 4) - { - case 3: - // Stretch this missle so it's 2 pixels wide and shifted one - // pixel to the left - myM1Mask = &TIATables::MxMask[myNUSIZ1 & 0x07] - [((myNUSIZ1 & 0x30) >> 4)|1][160 - ((myPOSM1-1) & 0xFF)]; - break; - case 2: - // Missle is disabled on this line - myM1Mask = &TIATables::DisabledMask[0]; - break; - default: - myM1Mask = &TIATables::MxMask[myNUSIZ1 & 0x07] - [(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFF)]; - break; - } - } - else - myM1Mask = &TIATables::MxMask[myNUSIZ1 & 0x07] - [(myNUSIZ1 & 0x30) >> 4][160 - (myPOSM1 & 0xFF)]; - - uInt8 enabledObjects = myEnabledObjects & myDisabledObjects; - uInt32 hpos = clocksFromStartOfScanLine - HBLANK; - for(; myFramePointer < ending; ++myFramePointer, ++hpos) - { - uInt8 enabled = ((enabledObjects & PFBit) && - (myPF & myPFMask[hpos])) ? PFBit : 0; - - if((enabledObjects & BLBit) && myBLMask[hpos]) - enabled |= BLBit; - - if((enabledObjects & P1Bit) && (myCurrentGRP1 & myP1Mask[hpos])) - enabled |= P1Bit; - - if((enabledObjects & M1Bit) && myM1Mask[hpos]) - enabled |= M1Bit; - - if((enabledObjects & P0Bit) && (myCurrentGRP0 & myP0Mask[hpos])) - enabled |= P0Bit; - - if((enabledObjects & M0Bit) && myM0Mask[hpos]) - enabled |= M0Bit; - - myCollision |= TIATables::CollisionMask[enabled]; - *myFramePointer = myColorPtr[myPriorityEncoder[hpos < 80 ? 0 : 1] - [enabled | myPlayfieldPriorityAndScore]]; - } - } - myFramePointer = ending; - } - - // Handle HMOVE blanks if they are enabled - if(myHMOVEBlankEnabled && (startOfScanLine < HBLANK + 8) && - (clocksFromStartOfScanLine < (HBLANK + 8))) - { - Int32 blanks = (HBLANK + 8) - clocksFromStartOfScanLine; - memset(oldFramePointer, myColorPtr[HBLANKColor], blanks); - - if((clocksToUpdate + clocksFromStartOfScanLine) >= (HBLANK + 8)) - myHMOVEBlankEnabled = false; - } - -// TODO - this needs to be updated to actually do as the comment suggests -#if 1 - // See if we're at the end of a scanline - if(myClocksToEndOfScanLine == 228) - { - // TODO - 01-21-99: 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 too slow. - mySuppressP0 = mySuppressP1 = 0; - } -#endif - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline void TIA::waitHorizontalSync() -{ - uInt32 cyclesToEndOfLine = 76 - ((mySystem->cycles() - - (myClockWhenFrameStarted / 3)) % 76); - - if(cyclesToEndOfLine < 76) - mySystem->incrementCycles(cyclesToEndOfLine); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline void TIA::waitHorizontalRSync() -{ - // 02-23-2013: RSYNC has now been updated to work correctly with - // Extra-Terrestrials. Fatal Run also uses RSYNC (in its VSYNC routine), - // and the NTSC prototype now displays 262 scanlines instead of 261. - // What is not emulated correctly is the "real time" effects. For example - // the VSYNC signal may not be 3 complete scanlines, although Stella will - // now count it as such. - // - // There are two extreme cases to demonstrate this "real time" variance - // effect over a proper three line VSYNC. 3*76 = 228 cycles properly needed: - // - // ====== SHORT TIME CASE ====== - // - // lda #3 ;2 @67 - // sta VSYNC ;3 @70 vsync starts - // sta RSYNC ;3 @73 +3 - // sta WSYNC ;3 @76 +6 - // ------------------------------ - // sta WSYNC ;3 @76 +82 - // ------------------------------ - // lda #0 ;2 @2 +84 - // sta VSYNC vsync ends - // - // ====== LONG TIME CASE ====== - // - // lda #3 ;2 @70 - // sta VSYNC ;3 @73 vsync starts - // sta RSYNC ;3 @74 +3 - // sta WSYNC ;3 @.. +81 2 cycles are added to previous line, and then - // WSYNC halts the new line delaying 78 cycles total! - //------------------------------ - // sta WSYNC ;3 @76 +157 - //------------------------------ - // lda #0 ;2 @2 +159 - // sta VSYNC vsync ends - - // The significance of the 'magic numbers' below is as follows (thanks to - // Eckhard Stolberg and Omegamatrix for explanation and implementation) - // - // Objects always get positioned three pixels further to the right after a - // WSYNC than they do after a RSYNC, but this is to be expected. Triggering - // WSYNC will halt the CPU until the horizontal sync counter wraps around to zero. - // Triggering RSYNC will reset the horizontal sync counter to zero immediately. - // But the warp-around will actually happen after one more cycle of this counter. - // Since the horizontal sync counter counts once every 4 pixels, one more CPU - // cycle occurs before the counter warps around to zero. Therefore the positioning - // code will hit RESPx one cycle sooner after a RSYNC than after a WSYNC. - - uInt32 cyclesToEndOfLine = 76 - ((mySystem->cycles() - - (myClockWhenFrameStarted / 3)) % 76); - - mySystem->incrementCycles(cyclesToEndOfLine-1); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::clearBuffers() -{ - memset(myCurrentFrameBuffer.get(), 0, 160 * 320); - memset(myPreviousFrameBuffer.get(), 0, 160 * 320); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline uInt8 TIA::dumpedInputPort(int resistance) -{ - if(resistance == Controller::minimumResistance) - { - return 0x80; - } - else if((resistance == Controller::maximumResistance) || myDumpEnabled) - { - return 0x00; - } - else - { - // Constant here is derived from '1.6 * 0.01e-6 * 228 / 3' - uInt32 needed = uInt32 - (1.216e-6 * resistance * myScanlineCountForLastFrame * myFramerate); - if((mySystem->cycles() - myDumpDisabledCycle) > needed) - return 0x80; - else - return 0x00; - } - return 0x00; // Make the compiler happy; we'll never reach this -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 TIA::peek(uInt16 addr) -{ - // Update frame to current color clock before we look at anything! - updateFrame(mySystem->cycles() * 3); - - // If pins are undriven, we start with the last databus value - // Otherwise, there is some randomness injected into the mix - // In either case, we start out with D7 and D6 disabled (the only - // valid bits in a TIA read), and selectively enable them - uInt8 value = 0x3F & (!myTIAPinsDriven ? mySystem->getDataBusState() : - mySystem->getDataBusState(0xFF)); - uInt16 collision = myCollision & uInt16(myCollisionEnabledMask); - - switch(addr & 0x000f) - { - case CXM0P: - value |= ((collision & Cx_M0P1) ? 0x80 : 0x00) | - ((collision & Cx_M0P0) ? 0x40 : 0x00); - break; - - case CXM1P: - value |= ((collision & Cx_M1P0) ? 0x80 : 0x00) | - ((collision & Cx_M1P1) ? 0x40 : 0x00); - break; - - case CXP0FB: - value |= ((collision & Cx_P0PF) ? 0x80 : 0x00) | - ((collision & Cx_P0BL) ? 0x40 : 0x00); - break; - - case CXP1FB: - value |= ((collision & Cx_P1PF) ? 0x80 : 0x00) | - ((collision & Cx_P1BL) ? 0x40 : 0x00); - break; - - case CXM0FB: - value |= ((collision & Cx_M0PF) ? 0x80 : 0x00) | - ((collision & Cx_M0BL) ? 0x40 : 0x00); - break; - - case CXM1FB: - value |= ((collision & Cx_M1PF) ? 0x80 : 0x00) | - ((collision & Cx_M1BL) ? 0x40 : 0x00); - break; - - case CXBLPF: - value = (value & 0x7F) | ((collision & Cx_BLPF) ? 0x80 : 0x00); - break; - - case CXPPMM: - value |= ((collision & Cx_P0P1) ? 0x80 : 0x00) | - ((collision & Cx_M0M1) ? 0x40 : 0x00); - break; - - case INPT0: - value = (value & 0x7F) | - dumpedInputPort(myConsole.leftController().read(Controller::Nine)); - break; - - case INPT1: - value = (value & 0x7F) | - dumpedInputPort(myConsole.leftController().read(Controller::Five)); - break; - - case INPT2: - value = (value & 0x7F) | - dumpedInputPort(myConsole.rightController().read(Controller::Nine)); - break; - - case INPT3: - value = (value & 0x7F) | - dumpedInputPort(myConsole.rightController().read(Controller::Five)); - break; - - case INPT4: - { - uInt8 button = (myConsole.leftController().read(Controller::Six) ? 0x80 : 0x00); - myINPT4 = (myVBLANK & 0x40) ? (myINPT4 & button) : button; - - value = (value & 0x7F) | myINPT4; - break; - } - - case INPT5: - { - uInt8 button = (myConsole.rightController().read(Controller::Six) ? 0x80 : 0x00); - myINPT5 = (myVBLANK & 0x40) ? (myINPT5 & button) : button; - - value = (value & 0x7F) | myINPT5; - break; - } - - default: - // This shouldn't happen, but if it does, we essentially just - // return the last databus value with bits D6 and D7 zeroed out - break; - } - return value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -bool TIA::poke(uInt16 addr, uInt8 value) -{ - addr = addr & 0x003f; - - Int32 clock = mySystem->cycles() * 3; - Int16 delay = TIATables::PokeDelay[addr]; - - // See if this is a poke to a PF register - if(delay == -1) - { - static uInt32 d[4] = {4, 5, 2, 3}; - Int32 x = ((clock - myClockWhenFrameStarted) % 228); - delay = d[(x / 3) & 3]; - } - - // Update frame to current CPU cycle before we make any changes! - updateFrame(clock + delay); - - // If a VSYNC hasn't been generated in time go ahead and end the frame - if(((clock - myClockWhenFrameStarted) / 228) >= Int32(myMaximumNumberOfScanlines)) - { - mySystem->m6502().stop(); - myPartialFrameFlag = false; - } - - switch(addr) - { - case VSYNC: // Vertical sync set-clear - { - myVSYNC = value; - - if(myVSYNC & 0x02) - { - // Indicate when VSYNC should be finished. This should really - // be 3 * 228 according to Atari's documentation, however, some - // games don't supply the full 3 scanlines of VSYNC. - myVSYNCFinishClock = clock + 228; - } - else if(!(myVSYNC & 0x02) && (clock >= myVSYNCFinishClock)) - { - // We're no longer interested in myVSYNCFinishClock - myVSYNCFinishClock = 0x7FFFFFFF; - - // Since we're finished with the frame tell the processor to halt - mySystem->m6502().stop(); - myPartialFrameFlag = false; - } - break; - } - - case VBLANK: // Vertical blank set-clear - { - // Is the dump to ground path being set for I0, I1, I2, and I3? - if(!(myVBLANK & 0x80) && (value & 0x80)) - { - myDumpEnabled = true; - } - // Is the dump to ground path being removed from I0, I1, I2, and I3? - else if((myVBLANK & 0x80) && !(value & 0x80)) - { - myDumpEnabled = false; - myDumpDisabledCycle = mySystem->cycles(); - } - - // Are the latches for I4 and I5 being reset? - if (!(myVBLANK & 0x40)) - myINPT4 = myINPT5 = 0x80; - - // Check for the first scanline at which VBLANK is disabled. - // Usually, this will be the first scanline to start drawing. - if(myStartScanline == 0 && !(value & 0x10)) - myStartScanline = scanlines(); - - myVBLANK = value; - break; - } - - case WSYNC: // Wait for leading edge of HBLANK - { - // It appears that the 6507 only halts during a read cycle so - // we test here for follow-on writes which should be ignored as - // far as halting the processor is concerned. - // - // TODO - 08-30-2006: This halting isn't correct since it's - // still halting on the original write. The 6507 emulation - // should be expanded to include a READY line. - if(mySystem->m6502().lastAccessWasRead()) - { - // Tell the cpu to waste the necessary amount of time - waitHorizontalSync(); - } - break; - } - - case RSYNC: // Reset horizontal sync counter - { - waitHorizontalRSync(); - break; - } - - case NUSIZ0: // Number-size of player-missle 0 - { - // TODO - 08-11-2009: determine correct delay instead of always - // using '8' in TIATables::PokeDelay - updateFrame(clock + 8); - - myNUSIZ0 = value; - mySuppressP0 = 0; - break; - } - - case NUSIZ1: // Number-size of player-missle 1 - { - // TODO - 08-11-2009: determine correct delay instead of always - // using '8' in TIATables::PokeDelay - updateFrame(clock + 8); - - myNUSIZ1 = value; - mySuppressP1 = 0; - break; - } - - case COLUP0: // Color-Luminance Player 0 - { - uInt8 color = value & 0xfe; - if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01)) - color |= 0x01; - - myColor[P0Color] = myColor[M0Color] = color; - break; - } - - case COLUP1: // Color-Luminance Player 1 - { - uInt8 color = value & 0xfe; - if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01)) - color |= 0x01; - - myColor[P1Color] = myColor[M1Color] = color; - break; - } - - case COLUPF: // Color-Luminance Playfield - { - uInt8 color = value & 0xfe; - if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01)) - color |= 0x01; - - myColor[PFColor] = myColor[BLColor] = color; - break; - } - - case COLUBK: // Color-Luminance Background - { - uInt8 color = value & 0xfe; - if(myColorLossEnabled && (myScanlineCountForLastFrame & 0x01)) - color |= 0x01; - - myColor[BKColor] = color; - break; - } - - case CTRLPF: // Control Playfield, Ball size, Collisions - { - myCTRLPF = value; - - // The playfield priority and score bits from the control register - // are accessed when the frame is being drawn. We precompute the - // necessary value here so we can save time while drawing. - myPlayfieldPriorityAndScore = ((myCTRLPF & 0x06) << 5); - - // Update the playfield mask based on reflection state if - // we're still on the left hand side of the playfield - if(((clock - myClockWhenFrameStarted) % 228) < (68 + 79)) - myPFMask = TIATables::PFMask[myCTRLPF & 0x01]; - - break; - } - - case REFP0: // Reflect Player 0 - { - // See if the reflection state of the player is being changed - if(((value & 0x08) && !myREFP0) || (!(value & 0x08) && myREFP0)) - { - myREFP0 = (value & 0x08); - myCurrentGRP0 = TIATables::GRPReflect[myCurrentGRP0]; - } - break; - } - - case REFP1: // Reflect Player 1 - { - // See if the reflection state of the player is being changed - if(((value & 0x08) && !myREFP1) || (!(value & 0x08) && myREFP1)) - { - myREFP1 = (value & 0x08); - myCurrentGRP1 = TIATables::GRPReflect[myCurrentGRP1]; - } - break; - } - - case PF0: // Playfield register byte 0 - { - myPF = (myPF & 0x000FFFF0) | ((value >> 4) & 0x0F); - - if(myPF == 0) - myEnabledObjects &= ~PFBit; - else - myEnabledObjects |= PFBit; - - #ifdef DEBUGGER_SUPPORT - uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); - if(dataAddr) - mySystem->setAccessFlags(dataAddr, CartDebug::PGFX); - #endif - break; - } - - case PF1: // Playfield register byte 1 - { - myPF = (myPF & 0x000FF00F) | (uInt32(value) << 4); - - if(myPF == 0) - myEnabledObjects &= ~PFBit; - else - myEnabledObjects |= PFBit; - - #ifdef DEBUGGER_SUPPORT - uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); - if(dataAddr) - mySystem->setAccessFlags(dataAddr, CartDebug::PGFX); - #endif - break; - } - - case PF2: // Playfield register byte 2 - { - myPF = (myPF & 0x00000FFF) | (uInt32(value) << 12); - - if(myPF == 0) - myEnabledObjects &= ~PFBit; - else - myEnabledObjects |= PFBit; - - #ifdef DEBUGGER_SUPPORT - uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); - if(dataAddr) - mySystem->setAccessFlags(dataAddr, CartDebug::PGFX); - #endif - break; - } - - case RESP0: // Reset Player 0 - { - Int32 hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; - Int16 newx; - - // Check if HMOVE is currently active - if(myCurrentHMOVEPos != 0x7FFFFFFF) - { - newx = hpos < 7 ? 3 : ((hpos + 5) % 160); - // If HMOVE is active, adjust for any remaining horizontal move clocks - applyActiveHMOVEMotion(hpos, newx, myMotionClockP0); - } - else - { - newx = hpos < -2 ? 3 : ((hpos + 5) % 160); - applyPreviousHMOVEMotion(hpos, newx, myHMP0); - } - if(myPOSP0 != newx) - { - // TODO - update player timing - - // Find out under what condition the player is being reset - delay = 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 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; - } - break; - } - - case RESP1: // Reset Player 1 - { - Int32 hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; - Int16 newx; - - // Check if HMOVE is currently active - if(myCurrentHMOVEPos != 0x7FFFFFFF) - { - newx = hpos < 7 ? 3 : ((hpos + 5) % 160); - // If HMOVE is active, adjust for any remaining horizontal move clocks - applyActiveHMOVEMotion(hpos, newx, myMotionClockP1); - } - else - { - newx = hpos < -2 ? 3 : ((hpos + 5) % 160); - applyPreviousHMOVEMotion(hpos, newx, myHMP1); - } - if(myPOSP1 != newx) - { - // TODO - update player timing - - // Find out under what condition the player is being reset - delay = 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 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; - } - break; - } - - case RESM0: // Reset Missle 0 - { - Int32 hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; - Int16 newx; - - // Check if HMOVE is currently active - if(myCurrentHMOVEPos != 0x7FFFFFFF) - { - newx = hpos < 7 ? 2 : ((hpos + 4) % 160); - // If HMOVE is active, adjust for any remaining horizontal move clocks - applyActiveHMOVEMotion(hpos, newx, myMotionClockM0); - } - else - { - newx = hpos < -1 ? 2 : ((hpos + 4) % 160); - applyPreviousHMOVEMotion(hpos, newx, myHMM0); - } - if(newx != myPOSM0) - { - myPOSM0 = newx; - } - break; - } - - case RESM1: // Reset Missle 1 - { - Int32 hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; - Int16 newx; - - // Check if HMOVE is currently active - if(myCurrentHMOVEPos != 0x7FFFFFFF) - { - newx = hpos < 7 ? 2 : ((hpos + 4) % 160); - // If HMOVE is active, adjust for any remaining horizontal move clocks - applyActiveHMOVEMotion(hpos, newx, myMotionClockM1); - } - else - { - newx = hpos < -1 ? 2 : ((hpos + 4) % 160); - applyPreviousHMOVEMotion(hpos, newx, myHMM1); - } - if(newx != myPOSM1) - { - myPOSM1 = newx; - } - break; - } - - case RESBL: // Reset Ball - { - Int32 hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; - - // Check if HMOVE is currently active - if(myCurrentHMOVEPos != 0x7FFFFFFF) - { - myPOSBL = hpos < 7 ? 2 : ((hpos + 4) % 160); - // If HMOVE is active, adjust for any remaining horizontal move clocks - applyActiveHMOVEMotion(hpos, myPOSBL, myMotionClockBL); - } - else - { - myPOSBL = hpos < 0 ? 2 : ((hpos + 4) % 160); - applyPreviousHMOVEMotion(hpos, myPOSBL, myHMBL); - } - break; - } - - case AUDC0: // Audio control 0 - { - myAUDC0 = value & 0x0f; - mySound.set(addr, value, mySystem->cycles()); - break; - } - - case AUDC1: // Audio control 1 - { - myAUDC1 = value & 0x0f; - mySound.set(addr, value, mySystem->cycles()); - break; - } - - case AUDF0: // Audio frequency 0 - { - myAUDF0 = value & 0x1f; - mySound.set(addr, value, mySystem->cycles()); - break; - } - - case AUDF1: // Audio frequency 1 - { - myAUDF1 = value & 0x1f; - mySound.set(addr, value, mySystem->cycles()); - break; - } - - case AUDV0: // Audio volume 0 - { - myAUDV0 = value & 0x0f; - mySound.set(addr, value, mySystem->cycles()); - break; - } - - case AUDV1: // Audio volume 1 - { - myAUDV1 = value & 0x0f; - mySound.set(addr, value, mySystem->cycles()); - break; - } - - case GRP0: // Graphics Player 0 - { - // Set player 0 graphics - myGRP0 = value; - - // Copy player 1 graphics into its delayed register - myDGRP1 = myGRP1; - - // Get the "current" data for GRP0 base on delay register and reflect - uInt8 grp0 = myVDELP0 ? myDGRP0 : myGRP0; - myCurrentGRP0 = myREFP0 ? TIATables::GRPReflect[grp0] : grp0; - - // Get the "current" data for GRP1 base on delay register and reflect - uInt8 grp1 = myVDELP1 ? myDGRP1 : myGRP1; - myCurrentGRP1 = myREFP1 ? TIATables::GRPReflect[grp1] : grp1; - - // Set enabled object bits - if(myCurrentGRP0 != 0) - myEnabledObjects |= P0Bit; - else - myEnabledObjects &= ~P0Bit; - - if(myCurrentGRP1 != 0) - myEnabledObjects |= P1Bit; - else - myEnabledObjects &= ~P1Bit; - - #ifdef DEBUGGER_SUPPORT - uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); - if(dataAddr) - mySystem->setAccessFlags(dataAddr, CartDebug::GFX); - #endif - break; - } - - case GRP1: // Graphics Player 1 - { - // Set player 1 graphics - myGRP1 = value; - - // Copy player 0 graphics into its delayed register - myDGRP0 = myGRP0; - - // Copy ball graphics into its delayed register - myDENABL = myENABL; - - // Get the "current" data for GRP0 base on delay register - uInt8 grp0 = myVDELP0 ? myDGRP0 : myGRP0; - myCurrentGRP0 = myREFP0 ? TIATables::GRPReflect[grp0] : grp0; - - // Get the "current" data for GRP1 base on delay register - uInt8 grp1 = myVDELP1 ? myDGRP1 : myGRP1; - myCurrentGRP1 = myREFP1 ? TIATables::GRPReflect[grp1] : grp1; - - // Set enabled object bits - if(myCurrentGRP0 != 0) - myEnabledObjects |= P0Bit; - else - myEnabledObjects &= ~P0Bit; - - if(myCurrentGRP1 != 0) - myEnabledObjects |= P1Bit; - else - myEnabledObjects &= ~P1Bit; - - if(myVDELBL ? myDENABL : myENABL) - myEnabledObjects |= BLBit; - else - myEnabledObjects &= ~BLBit; - - #ifdef DEBUGGER_SUPPORT - uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); - if(dataAddr) - mySystem->setAccessFlags(dataAddr, CartDebug::GFX); - #endif - break; - } - - case ENAM0: // Enable Missile 0 graphics - { - myENAM0 = value & 0x02; - - if(myENAM0 && !myRESMP0) - myEnabledObjects |= M0Bit; - else - myEnabledObjects &= ~M0Bit; - break; - } - - case ENAM1: // Enable Missile 1 graphics - { - myENAM1 = value & 0x02; - - if(myENAM1 && !myRESMP1) - myEnabledObjects |= M1Bit; - else - myEnabledObjects &= ~M1Bit; - break; - } - - case ENABL: // Enable Ball graphics - { - myENABL = value & 0x02; - - if(myVDELBL ? myDENABL : myENABL) - myEnabledObjects |= BLBit; - else - myEnabledObjects &= ~BLBit; - - break; - } - - case HMP0: // Horizontal Motion Player 0 - { - pokeHMP0(value, clock); - break; - } - - case HMP1: // Horizontal Motion Player 1 - { - pokeHMP1(value, clock); - break; - } - - case HMM0: // Horizontal Motion Missle 0 - { - pokeHMM0(value, clock); - break; - } - - case HMM1: // Horizontal Motion Missle 1 - { - pokeHMM1(value, clock); - break; - } - - case HMBL: // Horizontal Motion Ball - { - pokeHMBL(value, clock); - break; - } - - case VDELP0: // Vertical Delay Player 0 - { - myVDELP0 = value & 0x01; - - uInt8 grp0 = myVDELP0 ? myDGRP0 : myGRP0; - myCurrentGRP0 = myREFP0 ? TIATables::GRPReflect[grp0] : grp0; - - if(myCurrentGRP0 != 0) - myEnabledObjects |= P0Bit; - else - myEnabledObjects &= ~P0Bit; - break; - } - - case VDELP1: // Vertical Delay Player 1 - { - myVDELP1 = value & 0x01; - - uInt8 grp1 = myVDELP1 ? myDGRP1 : myGRP1; - myCurrentGRP1 = myREFP1 ? TIATables::GRPReflect[grp1] : grp1; - - if(myCurrentGRP1 != 0) - myEnabledObjects |= P1Bit; - else - myEnabledObjects &= ~P1Bit; - break; - } - - case VDELBL: // Vertical Delay Ball - { - myVDELBL = value & 0x01; - - if(myVDELBL ? myDENABL : myENABL) - myEnabledObjects |= BLBit; - else - myEnabledObjects &= ~BLBit; - break; - } - - case RESMP0: // Reset missle 0 to player 0 - { - if(myRESMP0 && !(value & 0x02)) - { - uInt16 middle = 4; - switch(myNUSIZ0 & 0x07) - { - // 1-pixel delay is taken care of in TIATables::PxMask - case 0x05: middle = 8; break; // double size - case 0x07: middle = 16; break; // quad size - } - myPOSM0 = myPOSP0 + middle; - if(myCurrentHMOVEPos != 0x7FFFFFFF) - { - myPOSM0 -= (8 - myMotionClockP0); - myPOSM0 += (8 - myMotionClockM0); - } - CLAMP_POS(myPOSM0); - } - myRESMP0 = value & 0x02; - - if(myENAM0 && !myRESMP0) - myEnabledObjects |= M0Bit; - else - myEnabledObjects &= ~M0Bit; - - break; - } - - case RESMP1: // Reset missle 1 to player 1 - { - if(myRESMP1 && !(value & 0x02)) - { - uInt16 middle = 4; - switch(myNUSIZ1 & 0x07) - { - // 1-pixel delay is taken care of in TIATables::PxMask - case 0x05: middle = 8; break; // double size - case 0x07: middle = 16; break; // quad size - } - myPOSM1 = myPOSP1 + middle; - if(myCurrentHMOVEPos != 0x7FFFFFFF) - { - myPOSM1 -= (8 - myMotionClockP1); - myPOSM1 += (8 - myMotionClockM1); - } - CLAMP_POS(myPOSM1); - } - myRESMP1 = value & 0x02; - - if(myENAM1 && !myRESMP1) - myEnabledObjects |= M1Bit; - else - myEnabledObjects &= ~M1Bit; - break; - } - - case HMOVE: // Apply horizontal motion - { - int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; - myCurrentHMOVEPos = hpos; - - // See if we need to enable the HMOVE blank bug - myHMOVEBlankEnabled = TIATables::HMOVEBlankEnableCycles[((clock - myClockWhenFrameStarted) % 228) / 3]; - - // Do we have to undo some of the already applied cycles from an - // active graphics latch? - if(hpos + HBLANK < 17 * 4) - { - Int16 cycle_fix = 17 - ((hpos + HBLANK + 7) / 4); - if(myHMP0mmr) myPOSP0 = (myPOSP0 + cycle_fix) % 160; - if(myHMP1mmr) myPOSP1 = (myPOSP1 + cycle_fix) % 160; - if(myHMM0mmr) myPOSM0 = (myPOSM0 + cycle_fix) % 160; - if(myHMM1mmr) myPOSM1 = (myPOSM1 + cycle_fix) % 160; - if(myHMBLmmr) myPOSBL = (myPOSBL + cycle_fix) % 160; - } - myHMP0mmr = myHMP1mmr = myHMM0mmr = myHMM1mmr = myHMBLmmr = false; - - // Can HMOVE activities be ignored? - if(hpos >= -5 && hpos < 97 ) - { - myMotionClockP0 = 0; - myMotionClockP1 = 0; - myMotionClockM0 = 0; - myMotionClockM1 = 0; - myMotionClockBL = 0; - myHMOVEBlankEnabled = false; - myCurrentHMOVEPos = 0x7FFFFFFF; - break; - } - - myMotionClockP0 = (myHMP0 ^ 0x80) >> 4; - myMotionClockP1 = (myHMP1 ^ 0x80) >> 4; - myMotionClockM0 = (myHMM0 ^ 0x80) >> 4; - myMotionClockM1 = (myHMM1 ^ 0x80) >> 4; - myMotionClockBL = (myHMBL ^ 0x80) >> 4; - - // Adjust number of graphics motion clocks for active display - if(hpos >= 97 && hpos < 151) - { - Int16 skip_motclks = (160 - myCurrentHMOVEPos - 6) >> 2; - myMotionClockP0 -= skip_motclks; - myMotionClockP1 -= skip_motclks; - myMotionClockM0 -= skip_motclks; - myMotionClockM1 -= skip_motclks; - myMotionClockBL -= skip_motclks; - if(myMotionClockP0 < 0) myMotionClockP0 = 0; - if(myMotionClockP1 < 0) myMotionClockP1 = 0; - if(myMotionClockM0 < 0) myMotionClockM0 = 0; - if(myMotionClockM1 < 0) myMotionClockM1 = 0; - if(myMotionClockBL < 0) myMotionClockBL = 0; - } - - if(hpos >= -56 && hpos < -5) - { - Int16 max_motclks = (7 - (myCurrentHMOVEPos + 5)) >> 2; - if(myMotionClockP0 > max_motclks) myMotionClockP0 = max_motclks; - if(myMotionClockP1 > max_motclks) myMotionClockP1 = max_motclks; - if(myMotionClockM0 > max_motclks) myMotionClockM0 = max_motclks; - if(myMotionClockM1 > max_motclks) myMotionClockM1 = max_motclks; - if(myMotionClockBL > max_motclks) myMotionClockBL = max_motclks; - } - - // Apply horizontal motion - if(hpos < -5 || hpos >= 157) - { - myPOSP0 += 8 - myMotionClockP0; - myPOSP1 += 8 - myMotionClockP1; - myPOSM0 += 8 - myMotionClockM0; - myPOSM1 += 8 - myMotionClockM1; - myPOSBL += 8 - myMotionClockBL; - } - - // Make sure positions are in range - CLAMP_POS(myPOSP0); - CLAMP_POS(myPOSP1); - CLAMP_POS(myPOSM0); - CLAMP_POS(myPOSM1); - CLAMP_POS(myPOSBL); - - // TODO - handle late HMOVE's - mySuppressP0 = mySuppressP1 = 0; - break; - } - - case HMCLR: // Clear horizontal motion registers - { - pokeHMP0(0, clock); - pokeHMP1(0, clock); - pokeHMM0(0, clock); - pokeHMM1(0, clock); - pokeHMBL(0, clock); - break; - } - - case CXCLR: // Clear collision latches - { - myCollision = 0; - break; - } - - default: - { -#ifdef DEBUG_ACCESSES - cerr << "BAD TIA Poke: " << hex << addr << endl; -#endif - break; - } - } - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// Note that the following methods to change the horizontal motion registers -// are not completely accurate. We should be taking care of the following -// explanation from A. Towers Hardware Notes: -// -// Much more interesting is this: if the counter has not yet -// reached the value in HMxx (or has reached it but not yet -// commited the comparison) and a value with at least one bit -// in common with all remaining internal counter states is -// written (zeros or ones), the stopping condition will never be -// reached and the object will be moved a full 15 pixels left. -// In addition to this, the HMOVE will complete without clearing -// the "more movement required" latch, and so will continue to send -// an additional clock signal every 4 CLK (during visible and -// non-visible parts of the scanline) until another HMOVE operation -// clears the latch. The HMCLR command does not reset these latches. -// -// This condition is what causes the 'starfield effect' in Cosmic Ark, -// and the 'snow' in Stay Frosty. Ideally, we'd trace the counter and -// do a compare every colour clock, updating the horizontal positions -// when applicable. We can save time by cheating, and noting that the -// effect only occurs for 'magic numbers' 0x70 and 0x80. -// -// Most of the ideas in these methods come from MESS. -// (used with permission from Wilbert Pol) -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::pokeHMP0(uInt8 value, Int32 clock) -{ - value &= 0xF0; - if(myHMP0 == value) - return; - - int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; - - // Check if HMOVE is currently active - if(myCurrentHMOVEPos != 0x7FFFFFFF && - hpos < std::min(myCurrentHMOVEPos + 6 + myMotionClockP0 * 4, 7)) - { - Int32 newMotion = (value ^ 0x80) >> 4; - // Check if new horizontal move can still be applied normally - if(newMotion > myMotionClockP0 || - hpos <= std::min(myCurrentHMOVEPos + 6 + newMotion * 4, 7)) - { - myPOSP0 -= (newMotion - myMotionClockP0); - myMotionClockP0 = newMotion; - } - else - { - myPOSP0 -= (15 - myMotionClockP0); - myMotionClockP0 = 15; - if(value != 0x70 && value != 0x80) - myHMP0mmr = true; - } - CLAMP_POS(myPOSP0); - // TODO - adjust player timing - } - myHMP0 = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::pokeHMP1(uInt8 value, Int32 clock) -{ - value &= 0xF0; - if(myHMP1 == value) - return; - - int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; - - // Check if HMOVE is currently active - if(myCurrentHMOVEPos != 0x7FFFFFFF && - hpos < std::min(myCurrentHMOVEPos + 6 + myMotionClockP1 * 4, 7)) - { - Int32 newMotion = (value ^ 0x80) >> 4; - // Check if new horizontal move can still be applied normally - if(newMotion > myMotionClockP1 || - hpos <= std::min(myCurrentHMOVEPos + 6 + newMotion * 4, 7)) - { - myPOSP1 -= (newMotion - myMotionClockP1); - myMotionClockP1 = newMotion; - } - else - { - myPOSP1 -= (15 - myMotionClockP1); - myMotionClockP1 = 15; - if(value != 0x70 && value != 0x80) - myHMP1mmr = true; - } - CLAMP_POS(myPOSP1); - // TODO - adjust player timing - } - myHMP1 = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::pokeHMM0(uInt8 value, Int32 clock) -{ - value &= 0xF0; - if(myHMM0 == value) - return; - - int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; - - // Check if HMOVE is currently active - if(myCurrentHMOVEPos != 0x7FFFFFFF && - hpos < std::min(myCurrentHMOVEPos + 6 + myMotionClockM0 * 4, 7)) - { - Int32 newMotion = (value ^ 0x80) >> 4; - // Check if new horizontal move can still be applied normally - if(newMotion > myMotionClockM0 || - hpos <= std::min(myCurrentHMOVEPos + 6 + newMotion * 4, 7)) - { - myPOSM0 -= (newMotion - myMotionClockM0); - myMotionClockM0 = newMotion; - } - else - { - myPOSM0 -= (15 - myMotionClockM0); - myMotionClockM0 = 15; - if(value != 0x70 && value != 0x80) - myHMM0mmr = true; - } - CLAMP_POS(myPOSM0); - } - myHMM0 = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::pokeHMM1(uInt8 value, Int32 clock) -{ - value &= 0xF0; - if(myHMM1 == value) - return; - - int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; - - // Check if HMOVE is currently active - if(myCurrentHMOVEPos != 0x7FFFFFFF && - hpos < std::min(myCurrentHMOVEPos + 6 + myMotionClockM1 * 4, 7)) - { - Int32 newMotion = (value ^ 0x80) >> 4; - // Check if new horizontal move can still be applied normally - if(newMotion > myMotionClockM1 || - hpos <= std::min(myCurrentHMOVEPos + 6 + newMotion * 4, 7)) - { - myPOSM1 -= (newMotion - myMotionClockM1); - myMotionClockM1 = newMotion; - } - else - { - myPOSM1 -= (15 - myMotionClockM1); - myMotionClockM1 = 15; - if(value != 0x70 && value != 0x80) - myHMM1mmr = true; - } - CLAMP_POS(myPOSM1); - } - myHMM1 = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIA::pokeHMBL(uInt8 value, Int32 clock) -{ - value &= 0xF0; - if(myHMBL == value) - return; - - int hpos = (clock - myClockWhenFrameStarted) % 228 - HBLANK; - - // Check if HMOVE is currently active - if(myCurrentHMOVEPos != 0x7FFFFFFF && - hpos < std::min(myCurrentHMOVEPos + 6 + myMotionClockBL * 4, 7)) - { - Int32 newMotion = (value ^ 0x80) >> 4; - // Check if new horizontal move can still be applied normally - if(newMotion > myMotionClockBL || - hpos <= std::min(myCurrentHMOVEPos + 6 + newMotion * 4, 7)) - { - myPOSBL -= (newMotion - myMotionClockBL); - myMotionClockBL = newMotion; - } - else - { - myPOSBL -= (15 - myMotionClockBL); - myMotionClockBL = 15; - if(value != 0x70 && value != 0x80) - myHMBLmmr = true; - } - CLAMP_POS(myPOSBL); - } - myHMBL = value; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// The following two methods apply extra clocks when a horizontal motion -// register (HMxx) is modified during an HMOVE, before waiting for the -// documented time of at least 24 CPU cycles. The applicable explanation -// from A. Towers Hardware Notes is as follows: -// -// In theory then the side effects of modifying the HMxx registers -// during HMOVE should be quite straight-forward. If the internal -// counter has not yet reached the value in HMxx, a new value greater -// than this (in 0-15 terms) will work normally. Conversely, if -// the counter has already reached the value in HMxx, new values -// will have no effect because the latch will have been cleared. -// -// Most of the ideas in these methods come from MESS. -// (used with permission from Wilbert Pol) -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline void TIA::applyActiveHMOVEMotion(int hpos, Int16& pos, Int32 motionClock) -{ - if(hpos < std::min(myCurrentHMOVEPos + 6 + 16 * 4, 7)) - { - Int32 decrements_passed = (hpos - (myCurrentHMOVEPos + 4)) >> 2; - pos += 8; - if((motionClock - decrements_passed) > 0) - { - pos -= (motionClock - decrements_passed); - if(pos < 0) pos += 160; - } - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -inline void TIA::applyPreviousHMOVEMotion(int hpos, Int16& pos, uInt8 motion) -{ - if(myPreviousHMOVEPos != 0x7FFFFFFF) - { - uInt8 motclk = (motion ^ 0x80) >> 4; - if(hpos <= myPreviousHMOVEPos - 228 + 5 + motclk * 4) - { - uInt8 motclk_passed = (hpos - (myPreviousHMOVEPos - 228 + 6)) >> 2; - pos -= (motclk - motclk_passed); - } - } -} - -} // namespace TIADefaultCore diff --git a/src/emucore/tia/core_default/TIA.hxx b/src/emucore/tia/core_default/TIA.hxx deleted file mode 100644 index c513aa2e4..000000000 --- a/src/emucore/tia/core_default/TIA.hxx +++ /dev/null @@ -1,645 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2016 by Bradford W. Mott, Stephen Anthony -// and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// $Id$ -//============================================================================ - -#ifndef TIA_DEFAULT_CORE_HXX -#define TIA_DEFAULT_CORE_HXX - -class Console; -class Settings; -class Sound; - -#include "AbstractTIA.hxx" -#include "bspf.hxx" -#include "System.hxx" -#include "TIATables.hxx" - -namespace TIADefaultCore { - -/** - This class is a device that emulates the Television Interface Adaptor - found in the Atari 2600 and 7800 consoles. The Television Interface - Adaptor is an integrated circuit designed to interface between an - eight bit microprocessor and a television video modulator. It converts - eight bit parallel data into serial outputs for the color, luminosity, - and composite sync required by a video modulator. - - This class outputs the serial data into a frame buffer which can then - be displayed on screen. - - @author Bradford W. Mott - @version $Id$ -*/ -class TIA : public AbstractTIA -{ - public: - - /** - Create a new TIA for the specified console - - @param console The console the TIA is associated with - @param sound The sound object the TIA is associated with - @param settings The settings object for this TIA device - */ - TIA(Console& console, Sound& sound, Settings& settings); - virtual ~TIA() = default; - - public: - /** - Reset device to its power-on state - */ - void reset() override; - - /** - Reset frame to current YStart/Height properties - */ - void frameReset() override; - - /** - Notification method invoked by the system right before the - system resets its cycle counter to zero. It may be necessary - to override this method for devices that remember cycle counts. - */ - void systemCyclesReset() override; - - /** - Install TIA in the specified system. Invoked by the system - when the TIA is attached to it. - - @param system The system the device should install itself in - */ - void install(System& system) override; - - /** - Install TIA in the specified system and device. Invoked by - the system when the TIA is attached to it. All devices - which invoke this method take responsibility for chaining - requests back to *this* device. - - @param system The system the device should install itself in - @param device The device responsible for this address space - */ - void installDelegate(System& system, Device& device) override; - - /** - Save the current state of this device to the given Serializer. - - @param out The Serializer object to use - @return False on any errors, else true - */ - bool save(Serializer& out) const override; - - /** - Load the current state of this device from the given Serializer. - - @param in The Serializer object to use - @return False on any errors, else true - */ - bool load(Serializer& in) override; - - /** - The following are very similar to save() and load(), except they - do a 'deeper' save of the display data itself. - - Normally, the internal framebuffer doesn't need to be saved to - a state file, since the file already contains all the information - needed to re-create it, starting from scanline 0. In effect, when a - state is loaded, the framebuffer is empty, and the next call to - update() generates valid framebuffer data. - - However, state files saved from the debugger need more information, - such as the exact state of the internal framebuffer itself *before* - we call update(), including if the display was in partial frame mode. - - Essentially, a normal state save has 'frame resolution', whereas - the debugger state save has 'cycle resolution', and hence needs - more information. The methods below save/load this extra info, - and eliminate having to save approx. 50K to normal state files. - */ - bool saveDisplay(Serializer& out) const override; - bool loadDisplay(Serializer& in) override; - - /** - Get a descriptor for the device name (used in error checking). - - @return The name of the object - */ - string name() const override { return "TIA"; } - - /** - Get the byte at the specified address - - @return The byte at the specified address - */ - uInt8 peek(uInt16 address) override; - - /** - Change the byte at the specified address to the given value - - @param address The address where the value should be stored - @param value The value to be stored at the address - - @return True if the poke changed the device address space, else false - */ - bool poke(uInt16 address, uInt8 value) override; - - /** - This method should be called at an interval corresponding to the - desired frame rate to update the TIA. Invoking this method will update - the graphics buffer and generate the corresponding audio samples. - */ - void update() override; - - /** - Answers the current frame buffer - - @return Pointer to the current frame buffer - */ - uInt8* currentFrameBuffer() const override - { return myCurrentFrameBuffer.get() + myFramePointerOffset + myCurrentFrameJitter; } - - /** - Answers the previous frame buffer - - @return Pointer to the previous frame buffer - */ - uInt8* previousFrameBuffer() const override - { return myPreviousFrameBuffer.get() + myFramePointerOffset; } - - /** - Answers the height of the frame buffer - */ - inline uInt32 height() const override { return myFrameHeight; } - inline uInt32 ystart() const override { return myFrameYStart; } - - /** - Changes the current Height/YStart properties. - Note that calls to these method(s) must be eventually followed by - ::frameReset() for the changes to take effect. - */ - void setHeight(uInt32 height) override { myFrameHeight = height; } - void setYStart(uInt32 ystart) override { myFrameYStart = ystart; } - - /** - Enables/disables auto-frame calculation. If enabled, the TIA - re-adjusts the framerate at regular intervals. - - @param mode Whether to enable or disable all auto-frame calculation - */ - void enableAutoFrame(bool mode) override { myAutoFrameEnabled = mode; } - - /** - Enables/disables color-loss for PAL modes only. - - @param mode Whether to enable or disable PAL color-loss mode - */ - void enableColorLoss(bool mode) override - { myColorLossEnabled = myFramerate <= 55 ? mode : false; } - - /** - Answers whether this TIA runs at NTSC or PAL scanrates, - based on how many frames of out the total count are PAL frames. - */ - bool isPAL() const override - { return double(myPALFrameCounter) / myFrameCounter >= (25.0/60.0); } - - /** - Answers the current color clock we've gotten to on this scanline. - - @return The current color clock - */ - uInt32 clocksThisLine() const override - { return ((mySystem->cycles() * 3) - myClockWhenFrameStarted) % 228; } - - /** - Answers the total number of scanlines the TIA generated in producing - the current frame buffer. For partial frames, this will be the - current scanline. - - @return The total number of scanlines generated - */ - uInt32 scanlines() const override - { return ((mySystem->cycles() * 3) - myClockWhenFrameStarted) / 228; } - - /** - Answers whether the TIA is currently in 'partial frame' mode - (we're in between a call of startFrame and endFrame). - - @return If we're in partial frame mode - */ - bool partialFrame() const override { return myPartialFrameFlag; } - - /** - Answers the first scanline at which drawing occured in the last frame. - - @return The starting scanline - */ - uInt32 startScanline() const override { return myStartScanline; } - - /** - Answers the current position of the virtual 'electron beam' used to - draw the TIA image. If not in partial frame mode, the position is - defined to be in the lower right corner (@ width/height of the screen). - Note that the coordinates are with respect to currentFrameBuffer(), - taking any YStart values into account. - - @return The x/y coordinates of the scanline electron beam, and whether - it is in the visible/viewable area of the screen - */ - bool scanlinePos(uInt16& x, uInt16& y) const override; - - /** - Enables/disable/toggle the specified (or all) TIA bit(s). Note that - disabling a graphical object also disables its collisions. - - @param mode 1/0 indicates on/off, and values greater than 1 mean - flip the bit from its current state - - @return Whether the bit was enabled or disabled - */ - bool toggleBit(TIABit b, uInt8 mode = 2) override; - bool toggleBits() override; - - /** - Enables/disable/toggle the specified (or all) TIA bit collision(s). - - @param mode 1/0 indicates on/off, and values greater than 1 mean - flip the collision from its current state - - @return Whether the collision was enabled or disabled - */ - bool toggleCollision(TIABit b, uInt8 mode = 2) override; - bool toggleCollisions() override; - - /** - Enables/disable/toggle 'fixed debug colors' mode. - - @param mode 1/0 indicates on/off, otherwise flip from - its current state - - @return Whether the mode was enabled or disabled - */ - bool toggleFixedColors(uInt8 mode = 2) override; - - /** - Enable/disable/query state of 'undriven/floating TIA pins'. - - @param mode 1/0 indicates on/off, otherwise return the current state - - @return Whether the mode was enabled or disabled - */ - bool driveUnusedPinsRandom(uInt8 mode = 2) override; - - /** - Enables/disable/toggle 'scanline jittering' mode, and set the - recovery 'factor'. - - @param mode 1/0 indicates on/off, otherwise flip from - its current state - - @return Whether the mode was enabled or disabled - */ - bool toggleJitter(uInt8 mode = 2) override; - void setJitterRecoveryFactor(Int32 f) override { myJitterRecoveryFactor = f; } - -#ifdef DEBUGGER_SUPPORT - /** - This method should be called to update the TIA with a new scanline. - */ - void updateScanline() override; - - /** - This method should be called to update the TIA with a new partial - scanline by stepping one CPU instruction. - */ - void updateScanlineByStep() override; - - /** - This method should be called to update the TIA with a new partial - scanline by tracing to target address. - */ - void updateScanlineByTrace(int target) override; -#endif - - private: - /** - Enables/disables all TIABit bits. Note that disabling a graphical - object also disables its collisions. - - @param mode Whether to enable or disable all bits - */ - void enableBits(bool mode); - - /** - Enables/disables all TIABit collisions. - - @param mode Whether to enable or disable all collisions - */ - void enableCollisions(bool mode); - - // Reset all instance variables to the initial state - void initialize(); - - // Update the current frame buffer to the specified color clock - void updateFrame(Int32 clock); - - // Waste cycles until the current scanline is finished - void waitHorizontalSync(); - - // Reset horizontal sync counter - void waitHorizontalRSync(); - - // Clear both internal TIA buffers to black (palette color 0) - void clearBuffers(); - - // Set up bookkeeping for the next frame - void startFrame(); - - // Update bookkeeping at end of frame - void endFrame(); - - // 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 - void applyActiveHMOVEMotion(int hpos, Int16& pos, Int32 motionClock); - - // Apply motion to registers when HMOVE was previously active - void applyPreviousHMOVEMotion(int hpos, Int16& pos, uInt8 motion); - - private: - // Console the TIA is associated with - Console& myConsole; - - // Sound object the TIA is associated with - Sound& mySound; - - // Settings object the TIA is associated with - Settings& mySettings; - - // Pointer to the current frame buffer - BytePtr myCurrentFrameBuffer; - - // Pointer to the previous frame buffer - BytePtr myPreviousFrameBuffer; - - // Pointer to the next pixel that will be drawn in the current frame buffer - uInt8* myFramePointer; - - // Indicates offset used by the exported frame buffer - // (the exported frame buffer is a vertical 'sliding window' of the actual buffer) - uInt32 myFramePointerOffset; - - // Indicates the number of 'colour clocks' offset from the base - // frame buffer pointer - // (this is used when loading state files with a 'partial' frame) - uInt32 myFramePointerClocks; - - // Indicated what scanline the frame should start being drawn at - uInt32 myFrameYStart; - - // Indicates the height of the frame in scanlines - uInt32 myFrameHeight; - - // Indicates offset in color clocks when display should stop - uInt32 myStopDisplayOffset; - - // Indicates color clocks when the current frame began - Int32 myClockWhenFrameStarted; - - // Indicates color clocks when frame should begin to be drawn - Int32 myClockStartDisplay; - - // Indicates color clocks when frame should stop being drawn - Int32 myClockStopDisplay; - - // Indicates color clocks when the frame was last updated - Int32 myClockAtLastUpdate; - - // Indicates how many color clocks remain until the end of - // current scanline. This value is valid during the - // displayed portion of the frame. - Int32 myClocksToEndOfScanLine; - - // Indicates the total number of scanlines generated by the last frame - uInt32 myScanlineCountForLastFrame; - - // Indicates the maximum number of scanlines to be generated for a frame - uInt32 myMaximumNumberOfScanlines; - - // Indicates potentially the first scanline at which drawing occurs - uInt32 myStartScanline; - - // Color clock when VSYNC ending causes a new frame to be started - Int32 myVSYNCFinishClock; - - uInt8 myVSYNC; // Holds the VSYNC register value - uInt8 myVBLANK; // Holds the VBLANK register value - - uInt8 myNUSIZ0; // Number and size of player 0 and missle 0 - uInt8 myNUSIZ1; // Number and size of player 1 and missle 1 - - uInt8 myPlayfieldPriorityAndScore; - uInt8 myPriorityEncoder[2][256]; - uInt8 myColor[8]; - uInt8 myFixedColor[8]; - uInt8* myColorPtr; - - uInt8 myCTRLPF; // Playfield control register - - bool myREFP0; // Indicates if player 0 is being reflected - bool myREFP1; // Indicates if player 1 is being reflected - - uInt32 myPF; // Playfield graphics (19-12:PF2 11-4:PF1 3-0:PF0) - - uInt8 myGRP0; // Player 0 graphics register - uInt8 myGRP1; // Player 1 graphics register - - uInt8 myDGRP0; // Player 0 delayed graphics register - uInt8 myDGRP1; // Player 1 delayed graphics register - - bool myENAM0; // 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 vertically delayed ball is enabled - - 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 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 - - // Determines whether specified collisions are enabled or disabled - // The lower 16 bits are and'ed with the collision register to mask out - // any collisions we don't want to be processed - // The upper 16 bits are used to store which objects is currently - // enabled or disabled - // This is necessary since there are 15 collision combinations which - // are controlled by 6 objects - uInt32 myCollisionEnabledMask; - - // Note that these position registers contain the color clock - // on which the object's serial output should begin (0 to 159) - Int16 myPOSP0; // Player 0 position register - Int16 myPOSP1; // Player 1 position register - Int16 myPOSM0; // Missle 0 position register - 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; - - // 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; - 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; - - // Graphics for Player 1 that should be displayed. This will be - // reflected if the player is being reflected. - uInt8 myCurrentGRP1; - - // It's VERY important that the BL, M0, M1, P0 and P1 current - // mask pointers are always on a uInt32 boundary. Otherwise, - // the TIA code will fail on a good number of CPUs. - const uInt8* myP0Mask; - const uInt8* myM0Mask; - const uInt8* myM1Mask; - const uInt8* myP1Mask; - const uInt8* myBLMask; - const uInt32* myPFMask; - - // Audio values; only used by TIADebug - uInt8 myAUDV0, myAUDV1, myAUDC0, myAUDC1, myAUDF0, myAUDF1; - - // Indicates when the dump for paddles was last set - Int32 myDumpDisabledCycle; - - // Indicates if the dump is current enabled for the paddles - bool myDumpEnabled; - - // Latches for INPT4 and INPT5 - uInt8 myINPT4, myINPT5; - - // 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 randomly driven high or low - // Otherwise, they take on the value previously on the databus - bool myTIAPinsDriven; - - // Bitmap of the objects that should be considered while drawing - uInt8 myEnabledObjects; - - // Determines whether specified bits (from TIABit) are enabled or disabled - // 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 - // contains an odd number of scanlines. - bool myColorLossEnabled; - - // Indicates whether we're done with the current frame. poke() clears this - // when VSYNC is strobed or the max scanlines/frame limit is hit. - bool myPartialFrameFlag; - - // Automatic framerate correction based on number of scanlines - bool myAutoFrameEnabled; - - // Number of total frames displayed by this TIA - uInt32 myFrameCounter; - - // Number of PAL frames displayed by this TIA - uInt32 myPALFrameCounter; - - // The framerate currently in use by the Console - float myFramerate; - - // Whether TIA bits/collisions are currently enabled/disabled - bool myBitsEnabled, myCollisionsEnabled; - - // Whether to enable jitter emulation - bool myJitterEnabled; - - // Derived from the difference between the scanline counts of the - // current and prior frames. If non-zero the next frame should jitter. - Int32 myNextFrameJitter; - - // Jitter amount for the current frame - Int32 myCurrentFrameJitter; - - // Large jitter values will take multiple frames to recover from - Int32 myJitterRecovery, myJitterRecoveryFactor; - - private: - // Following constructors and assignment operators not supported - TIA() = delete; - TIA(const TIA&) = delete; - TIA(TIA&&) = delete; - TIA& operator=(const TIA&) = delete; - TIA& operator=(TIA&&) = delete; -}; - -} // namespace TIADefaultCore - -#endif diff --git a/src/emucore/tia/core_default/TIATables.cxx b/src/emucore/tia/core_default/TIATables.cxx deleted file mode 100644 index efb1a32c0..000000000 --- a/src/emucore/tia/core_default/TIATables.cxx +++ /dev/null @@ -1,730 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2016 by Bradford W. Mott, Stephen Anthony -// and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// $Id$ -//============================================================================ - -#include - -#include "bspf.hxx" -#include "TIATables.hxx" - -namespace TIADefaultCore { - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIATables::computeAllTables() -{ - memset(DisabledMask, 0, 640); - buildCollisionMaskTable(); - buildPxMaskTable(); - buildMxMaskTable(); - buildBLMaskTable(); - buildPFMaskTable(); - buildGRPReflectTable(); - buildPxPosResetWhenTable(); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIATables::buildCollisionMaskTable() -{ - for(uInt8 i = 0; i < 64; ++i) - { - CollisionMask[i] = 0; - - if((i & M0Bit) && (i & P1Bit)) // M0-P1 - CollisionMask[i] |= Cx_M0P1; - - if((i & M0Bit) && (i & P0Bit)) // M0-P0 - CollisionMask[i] |= Cx_M0P0; - - if((i & M1Bit) && (i & P0Bit)) // M1-P0 - CollisionMask[i] |= Cx_M1P0; - - if((i & M1Bit) && (i & P1Bit)) // M1-P1 - CollisionMask[i] |= Cx_M1P1; - - if((i & P0Bit) && (i & PFBit)) // P0-PF - CollisionMask[i] |= Cx_P0PF; - - if((i & P0Bit) && (i & BLBit)) // P0-BL - CollisionMask[i] |= Cx_P0BL; - - if((i & P1Bit) && (i & PFBit)) // P1-PF - CollisionMask[i] |= Cx_P1PF; - - if((i & P1Bit) && (i & BLBit)) // P1-BL - CollisionMask[i] |= Cx_P1BL; - - if((i & M0Bit) && (i & PFBit)) // M0-PF - CollisionMask[i] |= Cx_M0PF; - - if((i & M0Bit) && (i & BLBit)) // M0-BL - CollisionMask[i] |= Cx_M0BL; - - if((i & M1Bit) && (i & PFBit)) // M1-PF - CollisionMask[i] |= Cx_M1PF; - - if((i & M1Bit) && (i & BLBit)) // M1-BL - CollisionMask[i] |= Cx_M1BL; - - if((i & BLBit) && (i & PFBit)) // BL-PF - CollisionMask[i] |= Cx_BLPF; - - if((i & P0Bit) && (i & P1Bit)) // P0-P1 - CollisionMask[i] |= Cx_P0P1; - - if((i & M0Bit) && (i & M1Bit)) // M0-M1 - CollisionMask[i] |= Cx_M0M1; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// [suppress mode:2][nusiz:8][pixel:320] -// suppress=1: suppress on -// suppress=0: suppress off -void TIATables::buildPxMaskTable() -{ - Int32 x, suppress, nusiz; - - // Set the player mask table to all zeros - for(nusiz = 0; nusiz < 8; ++nusiz) - for(x = 0; x < 160; ++x) - PxMask[0][nusiz][x] = PxMask[1][nusiz][x] = 0x00; - - // Now, compute the player mask table - for(suppress = 0; suppress < 2; ++suppress) - { - for(nusiz = 0; nusiz < 8; ++nusiz) - { - for(x = 0; x < 160 + 72; ++x) - { - // nusiz: - // 0: one copy - // 1: two copies-close - // 2: two copies-med - // 3: three copies-close - // 4: two copies-wide - // 5: double size player - // 6: 3 copies medium - // 7: quad sized player - switch(nusiz) - { - case 0x00: - if((suppress == 0) && (x >= 0) && (x < 8)) - PxMask[suppress][nusiz][x % 160] = 0x80 >> x; - break; - - case 0x01: - if((suppress == 0) && (x >= 0) && (x < 8)) - PxMask[suppress][nusiz][x % 160] = 0x80 >> x; - else if(((x - 16) >= 0) && ((x - 16) < 8)) - PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 16); - break; - - case 0x02: - if((suppress == 0) && (x >= 0) && (x < 8)) - PxMask[suppress][nusiz][x % 160] = 0x80 >> x; - else if(((x - 32) >= 0) && ((x - 32) < 8)) - PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 32); - break; - - case 0x03: - if((suppress == 0) && (x >= 0) && (x < 8)) - PxMask[suppress][nusiz][x % 160] = 0x80 >> x; - else if(((x - 16) >= 0) && ((x - 16) < 8)) - PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 16); - else if(((x - 32) >= 0) && ((x - 32) < 8)) - PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 32); - break; - - case 0x04: - if((suppress == 0) && (x >= 0) && (x < 8)) - PxMask[suppress][nusiz][x % 160] = 0x80 >> x; - else if(((x - 64) >= 0) && ((x - 64) < 8)) - PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 64); - break; - - case 0x05: - // For some reason in double size nusiz the player's output - // is delayed by one pixel thus we use > instead of >= - if((suppress == 0) && (x > 0) && (x <= 16)) - PxMask[suppress][nusiz][x % 160] = 0x80 >> ((x - 1)/2); - break; - - case 0x06: - if((suppress == 0) && (x >= 0) && (x < 8)) - PxMask[suppress][nusiz][x % 160] = 0x80 >> x; - else if(((x - 32) >= 0) && ((x - 32) < 8)) - PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 32); - else if(((x - 64) >= 0) && ((x - 64) < 8)) - PxMask[suppress][nusiz][x % 160] = 0x80 >> (x - 64); - break; - - case 0x07: - // For some reason in quad size nusiz the player's output - // is delayed by one pixel thus we use > instead of >= - if((suppress == 0) && (x > 0) && (x <= 32)) - PxMask[suppress][nusiz][x % 160] = 0x80 >> ((x - 1)/4); - break; - } - } - - // Copy data into wrap-around area - for(x = 0; x < 160; ++x) - PxMask[suppress][nusiz][x + 160] = PxMask[suppress][nusiz][x]; - } - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// [number:8][size:5][pixel:320] -void TIATables::buildMxMaskTable() -{ - Int32 x, size, number; - - // Clear the missle table to start with - for(number = 0; number < 8; ++number) - for(size = 0; size < 5; ++size) - for(x = 0; x < 160; ++x) - MxMask[number][size][x] = false; - - for(number = 0; number < 8; ++number) - { - for(size = 0; size < 5; ++size) - { - for(x = 0; x < 160 + 72; ++x) - { - // For the following, size index = 4 is almost exactly the same as - // index = 2; that is, 1 << 2, or 4 colour clocks wide - // To simulate the weirdness in the Cosmic Ark starfield effect, - // each group of 4 pixels has its 3rd pixel blanked - switch(number) - { - // Only one copy of the missle - case 0x00: - case 0x05: - case 0x07: - if(size != 4) - { - if((x >= 0) && (x < (1 << size))) - MxMask[number][size][x % 160] = true; - } - else - { - if((x >= 0) && (x < (1 << 2))) - MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); - } - break; - - // Two copies - close - case 0x01: - if(size != 4) - { - if((x >= 0) && (x < (1 << size))) - MxMask[number][size][x % 160] = true; - else if(((x - 16) >= 0) && ((x - 16) < (1 << size))) - MxMask[number][size][x % 160] = true; - } - else - { - if((x >= 0) && (x < (1 << 2))) - MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); - else if(((x - 16) >= 0) && ((x - 16) < (1 << 2))) - MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); - } - break; - - // Two copies - medium - case 0x02: - if(size != 4) - { - if((x >= 0) && (x < (1 << size))) - MxMask[number][size][x % 160] = true; - else if(((x - 32) >= 0) && ((x - 32) < (1 << size))) - MxMask[number][size][x % 160] = true; - } - else - { - if((x >= 0) && (x < (1 << 2))) - MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); - else if(((x - 32) >= 0) && ((x - 32) < (1 << 2))) - MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); - } - break; - - // Three copies - close - case 0x03: - if(size != 4) - { - if((x >= 0) && (x < (1 << size))) - MxMask[number][size][x % 160] = true; - else if(((x - 16) >= 0) && ((x - 16) < (1 << size))) - MxMask[number][size][x % 160] = true; - else if(((x - 32) >= 0) && ((x - 32) < (1 << size))) - MxMask[number][size][x % 160] = true; - } - else - { - if((x >= 0) && (x < (1 << 2))) - MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); - else if(((x - 16) >= 0) && ((x - 16) < (1 << 2))) - MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); - else if(((x - 32) >= 0) && ((x - 32) < (1 << 2))) - MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); - } - break; - - // Two copies - wide - case 0x04: - if(size != 4) - { - if((x >= 0) && (x < (1 << size))) - MxMask[number][size][x % 160] = true; - else if(((x - 64) >= 0) && ((x - 64) < (1 << size))) - MxMask[number][size][x % 160] = true; - } - else - { - if((x >= 0) && (x < (1 << 2))) - MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); - else if(((x - 64) >= 0) && ((x - 64) < (1 << 2))) - MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); - } - break; - - // Three copies - medium - case 0x06: - if(size != 4) - { - if((x >= 0) && (x < (1 << size))) - MxMask[number][size][x % 160] = true; - else if(((x - 32) >= 0) && ((x - 32) < (1 << size))) - MxMask[number][size][x % 160] = true; - else if(((x - 64) >= 0) && ((x - 64) < (1 << size))) - MxMask[number][size][x % 160] = true; - } - else - { - if((x >= 0) && (x < (1 << 2))) - MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); - else if(((x - 32) >= 0) && ((x - 32) < (1 << 2))) - MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); - else if(((x - 64) >= 0) && ((x - 64) < (1 << 2))) - MxMask[number][4][x % 160] = ((x - 2) % 4 == 0 ? false : true); - } - break; - } - } - - // Copy data into wrap-around area - for(x = 0; x < 160; ++x) - MxMask[number][size][x + 160] = - MxMask[number][size][x]; - } - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// [size:4][pixel:320] -void TIATables::buildBLMaskTable() -{ - for(Int32 size = 0; size < 4; ++size) - { - Int32 x; - - // Set all of the masks to false to start with - for(x = 0; x < 160; ++x) - BLMask[size][x] = false; - - // Set the necessary fields true - for(x = 0; x < 160 + 8; ++x) - if((x >= 0) && (x < (1 << size))) - BLMask[size][x % 160] = true; - - // Copy fields into the wrap-around area of the mask - for(x = 0; x < 160; ++x) - BLMask[size][x + 160] = BLMask[size][x]; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// [reflect:2][pixel:160] -// reflect=1: reflection on -// reflect=0: reflection off -void TIATables::buildPFMaskTable() -{ - Int32 x; - - // Compute playfield mask table for non-reflected mode - for(x = 0; x < 160; ++x) - { - if(x < 16) - PFMask[0][x] = 0x00001 << (x >> 2); - else if(x < 48) - PFMask[0][x] = 0x00800 >> ((x - 16) >> 2); - else if(x < 80) - PFMask[0][x] = 0x01000 << ((x - 48) >> 2); - else if(x < 96) - PFMask[0][x] = 0x00001 << ((x - 80) >> 2); - else if(x < 128) - PFMask[0][x] = 0x00800 >> ((x - 96) >> 2); - else if(x < 160) - PFMask[0][x] = 0x01000 << ((x - 128) >> 2); - } - - // Compute playfield mask table for reflected mode - for(x = 0; x < 160; ++x) - { - if(x < 16) - PFMask[1][x] = 0x00001 << (x >> 2); - else if(x < 48) - PFMask[1][x] = 0x00800 >> ((x - 16) >> 2); - else if(x < 80) - PFMask[1][x] = 0x01000 << ((x - 48) >> 2); - else if(x < 112) - PFMask[1][x] = 0x80000 >> ((x - 80) >> 2); - else if(x < 144) - PFMask[1][x] = 0x00010 << ((x - 112) >> 2); - else if(x < 160) - PFMask[1][x] = 0x00008 >> ((x - 144) >> 2); - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void TIATables::buildGRPReflectTable() -{ - for(uInt16 i = 0; i < 256; ++i) - { - uInt8 r = 0; - - for(uInt16 t = 1; t <= 128; t <<= 1) - r = (r << 1) | ((i & t) ? 0x01 : 0x00); - - GRPReflect[i] = r; - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// [nusiz:8][old pixel:160][new pixel:160] -void TIATables::buildPxPosResetWhenTable() -{ - uInt32 nusiz, oldx, newx; - - // Loop through all player nusizs, all old player positions, and all new - // player positions and determine where the new position is located: - // 1 means the new position is within the display of an old copy of the - // player, -1 means the new position is within the delay portion of an - // old copy of the player, and 0 means it's neither of these two - for(nusiz = 0; nusiz < 8; ++nusiz) - { - for(oldx = 0; oldx < 160; ++oldx) - { - // Set everything to 0 for non-delay/non-display section - for(newx = 0; newx < 160; ++newx) - PxPosResetWhen[nusiz][oldx][newx] = 0; - - // Now, we'll set the entries for non-delay/non-display section - for(newx = 0; newx < 160 + 72 + 5; ++newx) - { - // nusiz: - // 0: one copy - // 1: two copies-close - // 2: two copies-med - // 3: three copies-close - // 4: two copies-wide - // 5: double size player - // 6: 3 copies medium - // 7: quad sized player - switch(nusiz) - { - case 0x00: - if((newx >= oldx) && (newx < (oldx + 4))) - PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - - else if((newx >= oldx + 4) && (newx < (oldx + 4 + 8))) - PxPosResetWhen[nusiz][oldx][newx % 160] = 1; - break; - - case 0x01: - if((newx >= oldx) && (newx < (oldx + 4))) - PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - else if((newx >= (oldx + 16)) && (newx < (oldx + 16 + 4))) - PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - - 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; - break; - - case 0x02: - if((newx >= oldx) && (newx < (oldx + 4))) - PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4))) - PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - - 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; - break; - - case 0x03: - if((newx >= oldx) && (newx < (oldx + 4))) - PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - else if((newx >= (oldx + 16)) && (newx < (oldx + 16 + 4))) - PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4))) - PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - - 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; - else if((newx >= oldx + 32 + 4) && (newx < (oldx + 32 + 4 + 8))) - PxPosResetWhen[nusiz][oldx][newx % 160] = 1; - break; - - case 0x04: - if((newx >= oldx) && (newx < (oldx + 4))) - PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - else if((newx >= (oldx + 64)) && (newx < (oldx + 64 + 4))) - PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - - 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; - break; - - case 0x05: - if((newx >= oldx) && (newx < (oldx + 4))) - PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - - else if((newx >= oldx + 4) && (newx < (oldx + 4 + 16))) - PxPosResetWhen[nusiz][oldx][newx % 160] = 1; - break; - - case 0x06: - if((newx >= oldx) && (newx < (oldx + 4))) - PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - else if((newx >= (oldx + 32)) && (newx < (oldx + 32 + 4))) - PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - else if((newx >= (oldx + 64)) && (newx < (oldx + 64 + 4))) - PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - - 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; - else if((newx >= oldx + 64 + 4) && (newx < (oldx + 64 + 4 + 8))) - PxPosResetWhen[nusiz][oldx][newx % 160] = 1; - break; - - case 0x07: - if((newx >= oldx) && (newx < (oldx + 4))) - PxPosResetWhen[nusiz][oldx][newx % 160] = -1; - - else if((newx >= oldx + 4) && (newx < (oldx + 4 + 32))) - PxPosResetWhen[nusiz][oldx][newx % 160] = 1; - break; - } - } - - // Let's do a sanity check on table entries - uInt32 s1 = 0, s2 = 0; - for(newx = 0; newx < 160; ++newx) - { - if(PxPosResetWhen[nusiz][oldx][newx] == -1) - ++s1; - if(PxPosResetWhen[nusiz][oldx][newx] == 1) - ++s2; - } - assert((s1 % 4 == 0) && (s2 % 8 == 0)); - } - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const Int16 TIATables::PokeDelay[64] = { - 0, // VSYNC - 1, // VBLANK (0) / 1 - 0, // WSYNC - 0, // RSYNC - 0, // NUSIZ0 - 0, // NUSIZ1 - 0, // COLUP0 - 0, // COLUP1 - 0, // COLUPF - 0, // COLUBK - 0, // CTRLPF - 1, // REFP0 - 1, // REFP1 - -1, // PF0 (4) / -1 - -1, // PF1 (4) / -1 - -1, // PF2 (4) / -1 - 0, // RESP0 - 0, // RESP1 - 8, // RESM0 (0) / 8 - 8, // RESM1 (0) / 8 - 0, // RESBL - 0, // AUDC0 (-1) / 0 - 0, // AUDC1 (-1) / 0 - 0, // AUDF0 (-1) / 0 - 0, // AUDF1 (-1) / 0 - 0, // AUDV0 (-1) / 0 - 0, // AUDV1 (-1) / 0 - 1, // GRP0 - 1, // GRP1 - 1, // ENAM0 - 1, // ENAM1 - 1, // ENABL - 0, // HMP0 - 0, // HMP1 - 0, // HMM0 - 0, // HMM1 - 0, // HMBL - 0, // VDELP0 - 0, // VDELP1 - 0, // VDELBL - 0, // RESMP0 - 0, // RESMP1 - 3, // HMOVE - 0, // HMCLR - 0, // CXCLR - // remaining values are undefined TIA write locations - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -const bool TIATables::HMOVEBlankEnableCycles[76] = { - true, true, true, true, true, true, true, true, true, true, // 00 - true, true, true, true, true, true, true, true, true, true, // 10 - true, false, false, false, false, false, false, false, false, false, // 20 - false, false, false, false, false, false, false, false, false, false, // 30 - false, false, false, false, false, false, false, false, false, false, // 40 - false, false, false, false, false, false, false, false, false, false, // 50 - false, false, false, false, false, false, false, false, false, false, // 60 - 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 - { 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK - { 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK - { 0, -1, -2, -3, -4, -5, -6, -7, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK - { 0, -1, -2, -3, -4, -5, -6, -6, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK - { 0, -1, -2, -3, -4, -5, -5, -5, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK - { 0, -1, -2, -3, -4, -5, -5, -5, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK - { 0, -1, -2, -3, -4, -4, -4, -4, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK - { 0, -1, -2, -3, -3, -3, -3, -3, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK - { 0, -1, -2, -2, -2, -2, -2, -2, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK - { 0, -1, -2, -2, -2, -2, -2, -2, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK - { 0, -1, -1, -1, -1, -1, -1, -1, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK - { 0, 0, 0, 0, 0, 0, 0, 0, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK - { 1, 1, 1, 1, 1, 1, 1, 1, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK - { 1, 1, 1, 1, 1, 1, 1, 1, 8, 7, 6, 5, 4, 3, 2, 1}, // HBLANK - { 2, 2, 2, 2, 2, 2, 2, 2, 8, 7, 6, 5, 4, 3, 2, 2}, // HBLANK - { 3, 3, 3, 3, 3, 3, 3, 3, 8, 7, 6, 5, 4, 3, 3, 3}, // HBLANK - { 4, 4, 4, 4, 4, 4, 4, 4, 8, 7, 6, 5, 4, 4, 4, 4}, // HBLANK - { 4, 4, 4, 4, 4, 4, 4, 4, 8, 7, 6, 5, 4, 4, 4, 4}, // HBLANK - { 5, 5, 5, 5, 5, 5, 5, 5, 8, 7, 6, 5, 5, 5, 5, 5}, // HBLANK - { 6, 6, 6, 6, 6, 6, 6, 6, 8, 7, 6, 6, 6, 6, 6, 6}, // HBLANK - { 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, 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, 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, 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, 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, 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, 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, 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}, - { 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, 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, 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, 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, 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, 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, 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, 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}, - { 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, 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, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, -1, -2, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, -1, -2, -3, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, -1, -2, -3, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, -1, -2, -3, -4, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, -1, -2, -3, -4, -5, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, -1, -2, -3, -4, -5, -6, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, 0, -1, -2, -3, -4, -5, -6, 0, 0, 0, 0, 0, 0, 0, 0}, - { 0, -1, -2, -3, -4, -5, -6, -7, 0, 0, 0, 0, 0, 0, 0, 0}, - {-1, -2, -3, -4, -5, -6, -7, -8, 0, 0, 0, 0, 0, 0, 0, 0}, - {-2, -3, -4, -5, -6, -7, -8, -9, 0, 0, 0, 0, 0, 0, 0, -1}, - {-2, -3, -4, -5, -6, -7, -8, -9, 0, 0, 0, 0, 0, 0, 0, -1}, - {-3, -4, -5, -6, -7, -8, -9,-10, 0, 0, 0, 0, 0, 0, -1, -2}, - {-4, -5, -6, -7, -8, -9,-10,-11, 0, 0, 0, 0, 0, -1, -2, -3}, - {-5, -6, -7, -8, -9,-10,-11,-12, 0, 0, 0, 0, -1, -2, -3, -4}, - {-5, -6, -7, -8, -9,-10,-11,-12, 0, 0, 0, 0, -1, -2, -3, -4}, - {-6, -7, -8, -9,-10,-11,-12,-13, 0, 0, 0, -1, -2, -3, -4, -5}, - {-7, -8, -9,-10,-11,-12,-13,-14, 0, 0, -1, -2, -3, -4, -5, -6}, - {-8, -9,-10,-11,-12,-13,-14,-15, 0, -1, -2, -3, -4, -5, -6, -7}, - {-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[2][8][320]; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 TIATables::MxMask[8][5][320]; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 TIATables::BLMask[4][320]; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt32 TIATables::PFMask[2][160]; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 TIATables::GRPReflect[256]; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt16 TIATables::CollisionMask[64]; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -uInt8 TIATables::DisabledMask[640]; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Int8 TIATables::PxPosResetWhen[8][160][160]; - -} // namespace TIADefaultCore \ No newline at end of file diff --git a/src/emucore/tia/core_default/TIATables.hxx b/src/emucore/tia/core_default/TIATables.hxx deleted file mode 100644 index c56c318b3..000000000 --- a/src/emucore/tia/core_default/TIATables.hxx +++ /dev/null @@ -1,122 +0,0 @@ -//============================================================================ -// -// SSSS tt lll lll -// SS SS tt ll ll -// SS tttttt eeee ll ll aaaa -// SSSS tt ee ee ll ll aa -// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" -// SS SS tt ee ll ll aa aa -// SSSS ttt eeeee llll llll aaaaa -// -// Copyright (c) 1995-2016 by Bradford W. Mott, Stephen Anthony -// and the Stella Team -// -// See the file "License.txt" for information on usage and redistribution of -// this file, and for a DISCLAIMER OF ALL WARRANTIES. -// -// $Id$ -//============================================================================ - -#ifndef TIA_DEFAULT_CORE_TABLES_HXX -#define TIA_DEFAULT_CORE_TABLES_HXX - -#include "bspf.hxx" -#include "TIATypes.hxx" - -/** - The TIA class uses some static tables that aren't dependent on the actual - TIA state. For code organization, it's better to place that functionality - here. - - @author Stephen Anthony - @version $Id$ -*/ - -namespace TIADefaultCore { - -class TIATables -{ - public: - /** - Compute all static tables used by the TIA - */ - static void computeAllTables(); - - // Player mask table - // [suppress mode][nusiz][pixel] - static uInt8 PxMask[2][8][320]; - - // Missle mask table (entries are true or false) - // [number][size][pixel] - // There are actually only 4 possible size combinations on a real system - // The fifth size is used for simulating the starfield effect in - // Cosmic Ark and Stay Frosty - static uInt8 MxMask[8][5][320]; - - // Ball mask table (entries are true or false) - // [size][pixel] - static uInt8 BLMask[4][320]; - - // Playfield mask table for reflected and non-reflected playfields - // [reflect, pixel] - static uInt32 PFMask[2][160]; - - // A mask table which can be used when an object is disabled - static uInt8 DisabledMask[640]; - - // Used to set the collision register to the correct value - static uInt16 CollisionMask[64]; - - // 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]; - - // Used to reflect a players graphics - static uInt8 GRPReflect[256]; - - // Indicates if player is being reset during delay, display or other times - // [nusiz][old pixel][new pixel] - static Int8 PxPosResetWhen[8][160][160]; - - private: - // Compute the collision decode table - static void buildCollisionMaskTable(); - - // Compute the player mask table - static void buildPxMaskTable(); - - // Compute the missle mask table - static void buildMxMaskTable(); - - // Compute the ball mask table - static void buildBLMaskTable(); - - // Compute playfield mask table - static void buildPFMaskTable(); - - // Compute the player reflect table - static void buildGRPReflectTable(); - - // Compute the player position reset when table - static void buildPxPosResetWhenTable(); - - private: - // Following constructors and assignment operators not supported - TIATables() = delete; - TIATables(const TIATables&) = delete; - TIATables(TIATables&&) = delete; - TIATables& operator=(const TIATables&) = delete; - TIATables& operator=(TIATables&&) = delete; -}; - -} // namespace TIADefaultCore - -#endif \ No newline at end of file diff --git a/src/emucore/tia/core_default/module.mk b/src/emucore/tia/core_default/module.mk deleted file mode 100644 index f66658626..000000000 --- a/src/emucore/tia/core_default/module.mk +++ /dev/null @@ -1,11 +0,0 @@ -MODULE := src/emucore/tia/core_default - -MODULE_OBJS := \ - src/emucore/tia/core_default/TIA.o \ - src/emucore/tia/core_default/TIATables.o - -MODULE_DIRS += \ - src/emucore/tia/core_default - -# Include common rules -include $(srcdir)/common.rules diff --git a/src/emucore/tia/core_6502ts/module.mk b/src/emucore/tia/module.mk similarity index 100% rename from src/emucore/tia/core_6502ts/module.mk rename to src/emucore/tia/module.mk