mirror of https://github.com/stella-emu/stella.git
Implement delay queue.
This commit is contained in:
parent
b874269065
commit
ea6abb0fe6
|
@ -51,4 +51,10 @@ namespace TIA6502tsCore {
|
||||||
myIndices[address] = index;
|
myIndices[address] = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DelayQueue::reset()
|
||||||
|
{
|
||||||
|
for (DelayQueueMember& member : myMembers)
|
||||||
|
member.clear();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace TIA6502tsCore
|
} // namespace TIA6502tsCore
|
|
@ -35,6 +35,8 @@ class DelayQueue {
|
||||||
|
|
||||||
void push(uInt8 address, uInt8 value, uInt8 delay);
|
void push(uInt8 address, uInt8 value, uInt8 delay);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
template<class T> void execute(T executor);
|
template<class T> void execute(T executor);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// 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 "FrameManager.hxx"
|
||||||
|
|
||||||
|
enum Metrics : uInt32 {
|
||||||
|
vblankNTSC = 40,
|
||||||
|
vblankPAL = 48,
|
||||||
|
kernelNTSC = 192,
|
||||||
|
kernelPAL = 228,
|
||||||
|
overscanNTSC = 30,
|
||||||
|
overscanPAL = 36,
|
||||||
|
vsync = 3,
|
||||||
|
visibleOverscan = 20,
|
||||||
|
maxUnderscan = 10,
|
||||||
|
maxFramesWithoutVsync = 50,
|
||||||
|
tvModeDetectionTolerance = 20
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr uInt32
|
||||||
|
frameLinesNTSC = Metrics::vsync + Metrics::vblankNTSC + Metrics::kernelNTSC + Metrics::overscanNTSC,
|
||||||
|
frameLinesPAL = Metrics::vsync + Metrics::vblankPAL + Metrics::kernelPAL + Metrics::overscanPAL;
|
||||||
|
|
||||||
|
namespace TIA6502tsCore {
|
||||||
|
|
||||||
|
FrameManager::FrameManager()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameManager::setOnFrameCompleteHandler(FrameManager::frameCompletionHandler handler)
|
||||||
|
{
|
||||||
|
myOnFrameComplete = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameManager::reset()
|
||||||
|
{
|
||||||
|
setTvMode(TvMode::ntsc);
|
||||||
|
setState(State::waitForVsyncStart);
|
||||||
|
|
||||||
|
myLineInState = 0;
|
||||||
|
myLinesWithoutVsync = 0;
|
||||||
|
myWaitForVsync = true;
|
||||||
|
myVsync = false;
|
||||||
|
myVblank = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameManager::nextLine()
|
||||||
|
{
|
||||||
|
myCurrentFrameTotalLines++;
|
||||||
|
myLineInState++;
|
||||||
|
|
||||||
|
switch (myState) {
|
||||||
|
case State::waitForVsyncStart:
|
||||||
|
case State::waitForVsyncEnd:
|
||||||
|
if (myLinesWithoutVsync > myMaxLinesWithoutVsync) {
|
||||||
|
myWaitForVsync = false;
|
||||||
|
setState(State::waitForFrameStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case State::waitForFrameStart:
|
||||||
|
if (myWaitForVsync) {
|
||||||
|
if (myLineInState >= (myVblank ? myVblankLines : myVblankLines - Metrics::maxUnderscan))
|
||||||
|
setState(State::frame);
|
||||||
|
} else {
|
||||||
|
if (!myVblank) {
|
||||||
|
setState(State::frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case State::frame:
|
||||||
|
if (myLineInState >= myFrameLines + Metrics::visibleOverscan) {
|
||||||
|
finalizeFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case State::overscan:
|
||||||
|
if (myLineInState >= myOverscanLines - Metrics::visibleOverscan) {
|
||||||
|
setState(myWaitForVsync ? State::waitForVsyncStart : State::waitForFrameStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw runtime_error("frame manager: invalid state");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameManager::setVblank(bool vblank)
|
||||||
|
{
|
||||||
|
myVblank = vblank;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameManager::setVsync(bool vsync)
|
||||||
|
{
|
||||||
|
if (!myWaitForVsync || vsync == myVsync) return;
|
||||||
|
|
||||||
|
myVsync = vsync;
|
||||||
|
|
||||||
|
switch (myState) {
|
||||||
|
case State::waitForVsyncStart:
|
||||||
|
case State::waitForFrameStart:
|
||||||
|
case State::overscan:
|
||||||
|
if (myVsync) setState(State::waitForVsyncEnd);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case State::waitForVsyncEnd:
|
||||||
|
if (!myVsync) {
|
||||||
|
setState(State::waitForFrameStart);
|
||||||
|
myLinesWithoutVsync = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case State::frame:
|
||||||
|
if (myVsync) finalizeFrame();
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw runtime_error("frame manager: invalid state");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FrameManager::isRendering() const {
|
||||||
|
return myState == State::frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameManager::TvMode FrameManager::tvMode() const {
|
||||||
|
return myMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FrameManager::vblank() const {
|
||||||
|
return myVblank;
|
||||||
|
}
|
||||||
|
|
||||||
|
uInt32 FrameManager::height() const {
|
||||||
|
return myKernelLines + Metrics::visibleOverscan;
|
||||||
|
}
|
||||||
|
|
||||||
|
uInt32 FrameManager::currentLine() const {
|
||||||
|
return myState == State::frame ? myLineInState : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameManager::setTvMode(FrameManager::TvMode mode)
|
||||||
|
{
|
||||||
|
if (mode == myMode) return;
|
||||||
|
|
||||||
|
myMode = mode;
|
||||||
|
|
||||||
|
switch (myMode) {
|
||||||
|
case TvMode::ntsc:
|
||||||
|
myVblankLines = Metrics::vblankNTSC;
|
||||||
|
myKernelLines = Metrics::kernelNTSC;
|
||||||
|
myOverscanLines = Metrics::overscanNTSC;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TvMode::pal:
|
||||||
|
myVblankLines = Metrics::vblankPAL;
|
||||||
|
myKernelLines = Metrics::kernelPAL;
|
||||||
|
myOverscanLines = Metrics::overscanPAL;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw runtime_error("frame manager: invalid TV mode");
|
||||||
|
}
|
||||||
|
|
||||||
|
myFrameLines = Metrics::vsync + myVblankLines + myKernelLines + myOverscanLines;
|
||||||
|
myMaxLinesWithoutVsync = myFrameLines * Metrics::maxFramesWithoutVsync;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameManager::setState(FrameManager::State state)
|
||||||
|
{
|
||||||
|
myState = state;
|
||||||
|
myLineInState = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameManager::finalizeFrame()
|
||||||
|
{
|
||||||
|
const uInt32
|
||||||
|
deltaNTSC = abs(Int32(myCurrentFrameTotalLines) - Int32(frameLinesNTSC)),
|
||||||
|
deltaPAL = abs(Int32(myCurrentFrameTotalLines) - Int32(frameLinesPAL));
|
||||||
|
|
||||||
|
if (std::min(deltaNTSC, deltaPAL) <= Metrics::tvModeDetectionTolerance) {
|
||||||
|
setTvMode(deltaNTSC <= deltaPAL ? TvMode::ntsc : TvMode::pal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (myOnFrameComplete) {
|
||||||
|
myOnFrameComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
myCurrentFrameTotalLines = 0;
|
||||||
|
setState(State::overscan);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace TIA6502tsCore
|
|
@ -0,0 +1,113 @@
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// 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_6502TS_CORE_FRAME_MANAGER
|
||||||
|
#define TIA_6502TS_CORE_FRAME_MANAGER
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include "bspf.hxx"
|
||||||
|
|
||||||
|
namespace TIA6502tsCore {
|
||||||
|
|
||||||
|
class FrameManager {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum TvMode {
|
||||||
|
pal, ntsc
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::function<void()> frameCompletionHandler;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
FrameManager();
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void setOnFrameCompleteHandler(frameCompletionHandler);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void nextLine();
|
||||||
|
|
||||||
|
void setVblank(bool vblank);
|
||||||
|
|
||||||
|
void setVsync(bool vsync);
|
||||||
|
|
||||||
|
bool isRendering() const;
|
||||||
|
|
||||||
|
TvMode tvMode() const;
|
||||||
|
|
||||||
|
bool vblank() const;
|
||||||
|
|
||||||
|
uInt32 height() const;
|
||||||
|
|
||||||
|
uInt32 currentLine() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum State {
|
||||||
|
waitForVsyncStart,
|
||||||
|
waitForVsyncEnd,
|
||||||
|
waitForFrameStart,
|
||||||
|
frame,
|
||||||
|
overscan
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void setTvMode(TvMode mode);
|
||||||
|
|
||||||
|
void setState(State state);
|
||||||
|
|
||||||
|
void finalizeFrame();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
frameCompletionHandler myOnFrameComplete;
|
||||||
|
|
||||||
|
TvMode myMode;
|
||||||
|
State myState;
|
||||||
|
bool myWaitForVsync;
|
||||||
|
uInt32 myLineInState;
|
||||||
|
uInt32 myLinesWithoutVsync;
|
||||||
|
uInt32 myCurrentFrameTotalLines;
|
||||||
|
|
||||||
|
bool myVsync;
|
||||||
|
bool myVblank;
|
||||||
|
|
||||||
|
uInt32 myVblankLines;
|
||||||
|
uInt32 myKernelLines;
|
||||||
|
uInt32 myOverscanLines;
|
||||||
|
uInt32 myFrameLines;
|
||||||
|
uInt32 myMaxLinesWithoutVsync;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
FrameManager(const FrameManager&) = delete;
|
||||||
|
FrameManager(FrameManager&&) = delete;
|
||||||
|
FrameManager& operator=(const FrameManager&) = delete;
|
||||||
|
FrameManager& operator=(FrameManager&&) = delete;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace TIA6502tsCore
|
||||||
|
|
||||||
|
#endif // TIA_6502TS_CORE_FRAME_MANAGER
|
|
@ -28,11 +28,19 @@ namespace TIA6502tsCore {
|
||||||
mySound(sound),
|
mySound(sound),
|
||||||
mySettings(settings),
|
mySettings(settings),
|
||||||
myDelayQueue(10, 20)
|
myDelayQueue(10, 20)
|
||||||
{}
|
{
|
||||||
|
myFrameManager.setOnFrameCompleteHandler(
|
||||||
|
[this] () {onFrameComplete();}
|
||||||
|
);
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: stub
|
// TODO: stub
|
||||||
void TIA::reset()
|
void TIA::reset()
|
||||||
{}
|
{
|
||||||
|
myDelayQueue.reset();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: stub
|
// TODO: stub
|
||||||
void TIA::systemCyclesReset()
|
void TIA::systemCyclesReset()
|
||||||
|
@ -218,6 +226,10 @@ namespace TIA6502tsCore {
|
||||||
void TIA::setJitterRecoveryFactor(Int32 f)
|
void TIA::setJitterRecoveryFactor(Int32 f)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
// TODO: stub
|
||||||
|
void TIA::onFrameComplete()
|
||||||
|
{}
|
||||||
|
|
||||||
// TODO: stub
|
// TODO: stub
|
||||||
void TIA::delayedWrite(uInt8 address, uInt8 value)
|
void TIA::delayedWrite(uInt8 address, uInt8 value)
|
||||||
{}
|
{}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "Settings.hxx"
|
#include "Settings.hxx"
|
||||||
#include "TIATypes.hxx"
|
#include "TIATypes.hxx"
|
||||||
#include "DelayQueue.hxx"
|
#include "DelayQueue.hxx"
|
||||||
|
#include "FrameManager.hxx"
|
||||||
|
|
||||||
class Console;
|
class Console;
|
||||||
|
|
||||||
|
@ -117,6 +118,8 @@ class TIA : public AbstractTIA {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void onFrameComplete();
|
||||||
|
|
||||||
void delayedWrite(uInt8 address, uInt8 value);
|
void delayedWrite(uInt8 address, uInt8 value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -129,6 +132,8 @@ class TIA : public AbstractTIA {
|
||||||
|
|
||||||
DelayQueue myDelayQueue;
|
DelayQueue myDelayQueue;
|
||||||
|
|
||||||
|
FrameManager myFrameManager;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
TIA() = delete;
|
TIA() = delete;
|
||||||
|
|
|
@ -3,7 +3,8 @@ MODULE := src/emucore/tia/core_6502ts
|
||||||
MODULE_OBJS := \
|
MODULE_OBJS := \
|
||||||
src/emucore/tia/core_6502ts/TIA.o \
|
src/emucore/tia/core_6502ts/TIA.o \
|
||||||
src/emucore/tia/core_6502ts/DelayQueueMember.o \
|
src/emucore/tia/core_6502ts/DelayQueueMember.o \
|
||||||
src/emucore/tia/core_6502ts/DelayQueue.o
|
src/emucore/tia/core_6502ts/DelayQueue.o \
|
||||||
|
src/emucore/tia/core_6502ts/FrameManager.o
|
||||||
|
|
||||||
|
|
||||||
MODULE_DIRS += \
|
MODULE_DIRS += \
|
||||||
|
|
Loading…
Reference in New Issue