Implement delay queue.

This commit is contained in:
Christian Speckner 2016-11-13 22:56:02 +01:00
parent b874269065
commit ea6abb0fe6
7 changed files with 362 additions and 3 deletions

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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)
{} {}

View File

@ -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;

View File

@ -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 += \