diff --git a/src/emucore/tia/core_6502ts/TIA.cxx b/src/emucore/tia/core_6502ts/TIA.cxx index 6fb02d676..a3625c05e 100644 --- a/src/emucore/tia/core_6502ts/TIA.cxx +++ b/src/emucore/tia/core_6502ts/TIA.cxx @@ -19,10 +19,10 @@ #include "TIA.hxx" #include "TIATypes.hxx" +#include "M6502.hxx" namespace TIA6502tsCore { -// TODO: stub TIA::TIA(Console& console, Sound& sound, Settings& settings) : myConsole(console), mySound(sound), @@ -33,22 +33,60 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings) [this] () {onFrameComplete();} ); + myCurrentFrameBuffer = make_ptr(160 * 320); + myPreviousFrameBuffer = make_ptr(160 * 320); + reset(); } -// TODO: stub void TIA::reset() { + myHblankCtr = 0; + myHctr = 0; + myMovementInProgress = false; + myExtendedHblank = false; + myMovementClock = 0; + myPriority = Priority::normal; + myHstate = HState::blank; + myIsFreshLine = true; + myCollisionMask = 0; + myLinesSinceChange = 0; + myCollisionUpdateRequired = false; + + myLastCycle = 0; + + mySound.reset(); myDelayQueue.reset(); + myFrameManager.reset(); } -// TODO: stub void TIA::systemCyclesReset() -{} +{ + uInt32 cycles = mySystem->cycles(); + + myLastCycle -= cycles; + mySound.adjustCycleCounter(-cycles); +} -// TODO: stub 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); +} + // TODO: stub bool TIA::save(Serializer& out) const @@ -74,10 +112,6 @@ bool TIA::poke(uInt16 address, uInt8 value) return false; } -// TODO: stub -void TIA::installDelegate(System& system, Device& device) -{} - // TODO: stub void TIA::frameReset() {} @@ -98,25 +132,22 @@ bool TIA::loadDisplay(Serializer& in) void TIA::update() {} -// TODO: stub uInt8* TIA::currentFrameBuffer() const { - return 0; + return myCurrentFrameBuffer.get(); } // TODO: stub uInt8* TIA::previousFrameBuffer() const { - return 0; + return myPreviousFrameBuffer.get(); } -// TODO: stub uInt32 TIA::height() const { - return 0; + return myFrameManager.height(); } -// TODO: stub uInt32 TIA::ystart() const { return 0; @@ -138,10 +169,9 @@ void TIA::enableAutoFrame(bool enabled) void TIA::enableColorLoss(bool enabled) {} -// TODO: stub bool TIA::isPAL() const { - return false; + return myFrameManager.tvMode() == FrameManager::TvMode::pal; } // TODO: stub @@ -159,7 +189,7 @@ uInt32 TIA::scanlines() const // TODO: stub bool TIA::partialFrame() const { - return false; + return myFrameManager.isRendering(); } // TODO: stub @@ -226,9 +256,109 @@ bool TIA::toggleJitter(uInt8 mode) void TIA::setJitterRecoveryFactor(Int32 f) {} -// TODO: stub +void TIA::cycle(uInt32 colorClocks) +{ + for (uInt32 i = 0; i < colorClocks; i++) { + myDelayQueue.execute( + [this] (uInt8 address, uInt8 value) {delayedWrite(address, value);} + ); + + myCollisionUpdateRequired = false; + + tickMovement(); + + if (myHstate == HState::blank) + tickHblank(); + else + tickHframe(); + + if (myCollisionUpdateRequired) updateCollision(); + } +} + +void TIA::tickMovement() +{ + if (myMovementInProgress) return; + + if ((myHctr & 0x03) == 0) { + myLinesSinceChange = 0; + + const bool apply = myHstate == HState::blank; + + bool m = false; + + // TODO: propagate movement to sprites + + myMovementInProgress = m; + myCollisionUpdateRequired = m; + + myMovementClock++; + } +} + +void TIA::tickHblank() +{ + if (myIsFreshLine) { + myHblankCtr = 0; + myIsFreshLine = false; + } + + if (++myHblankCtr >= 68) myHstate = HState::frame; +} + +void TIA::tickHframe() +{ + const uInt32 y = myFrameManager.currentLine(); + const bool lineNotCached = myLinesSinceChange < 2 || y == 0; + const uInt32 x = myHctr - 68; + + myCollisionUpdateRequired = lineNotCached; + + // TODO: playfield tick + + // TODO: render sprites + + // TODO: tick sprites + + if (myFrameManager.isRendering()) renderPixel(x, y, lineNotCached); + + if (++myHctr >= 228) nextLine(); +} + +void TIA::nextLine() +{ + myHctr = 0; + myLinesSinceChange++; + + myHstate = HState::blank; + myIsFreshLine = true; + myExtendedHblank = false; + + myFrameManager.nextLine(); +} + +void TIA::updateCollision() +{ + // TODO: update collision mask with sprite masks +} + +void TIA::renderPixel(uInt32 x, uInt32 y, bool lineNotCached) +{ + if (lineNotCached) { + uInt8 color = 0; + + // TODO: determine color from sprites + + myCurrentFrameBuffer.get()[y * 160 + x] = myFrameManager.vblank() ? 0 : color; + } else { + myCurrentFrameBuffer.get()[y * 160 + x] = myCurrentFrameBuffer.get()[(y-1) * 160 + x]; + } +} + void TIA::onFrameComplete() -{} +{ + mySystem->m6502().stop(); +} // TODO: stub void TIA::delayedWrite(uInt8 address, uInt8 value) diff --git a/src/emucore/tia/core_6502ts/TIA.hxx b/src/emucore/tia/core_6502ts/TIA.hxx index 9d0a5e096..2d7f77ec1 100644 --- a/src/emucore/tia/core_6502ts/TIA.hxx +++ b/src/emucore/tia/core_6502ts/TIA.hxx @@ -118,6 +118,26 @@ class TIA : public AbstractTIA { private: + enum HState {blank, frame}; + + enum Priority {normal, inverted}; + + private: + + void cycle(uInt32 colorClocks); + + void tickMovement(); + + void tickHblank(); + + void tickHframe(); + + void updateCollision(); + + void renderPixel(uInt32 x, uInt32 y, bool lineNotCached); + + void nextLine(); + void onFrameComplete(); void delayedWrite(uInt8 address, uInt8 value); @@ -125,15 +145,34 @@ class TIA : public AbstractTIA { private: Console& myConsole; - Sound& mySound; - Settings& mySettings; DelayQueue myDelayQueue; - FrameManager myFrameManager; + HState myHstate; + bool myIsFreshLine; + + uInt32 myHblankCtr; + uInt32 myHctr; + + bool myCollisionUpdateRequired; + uInt32 myCollisionMask; + + uInt32 myMovementClock; + bool myMovementInProgress; + bool myExtendedHblank; + + uInt32 myLinesSinceChange; + + Priority myPriority; + + uInt32 myLastCycle; + + BytePtr myCurrentFrameBuffer; + BytePtr myPreviousFrameBuffer; + private: TIA() = delete;