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;
|
||||
}
|
||||
|
||||
void DelayQueue::reset()
|
||||
{
|
||||
for (DelayQueueMember& member : myMembers)
|
||||
member.clear();
|
||||
}
|
||||
|
||||
} // namespace TIA6502tsCore
|
|
@ -35,6 +35,8 @@ class DelayQueue {
|
|||
|
||||
void push(uInt8 address, uInt8 value, uInt8 delay);
|
||||
|
||||
void reset();
|
||||
|
||||
template<class T> void execute(T executor);
|
||||
|
||||
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),
|
||||
mySettings(settings),
|
||||
myDelayQueue(10, 20)
|
||||
{}
|
||||
{
|
||||
myFrameManager.setOnFrameCompleteHandler(
|
||||
[this] () {onFrameComplete();}
|
||||
);
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
// TODO: stub
|
||||
void TIA::reset()
|
||||
{}
|
||||
{
|
||||
myDelayQueue.reset();
|
||||
}
|
||||
|
||||
// TODO: stub
|
||||
void TIA::systemCyclesReset()
|
||||
|
@ -218,6 +226,10 @@ namespace TIA6502tsCore {
|
|||
void TIA::setJitterRecoveryFactor(Int32 f)
|
||||
{}
|
||||
|
||||
// TODO: stub
|
||||
void TIA::onFrameComplete()
|
||||
{}
|
||||
|
||||
// TODO: stub
|
||||
void TIA::delayedWrite(uInt8 address, uInt8 value)
|
||||
{}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "Settings.hxx"
|
||||
#include "TIATypes.hxx"
|
||||
#include "DelayQueue.hxx"
|
||||
#include "FrameManager.hxx"
|
||||
|
||||
class Console;
|
||||
|
||||
|
@ -117,6 +118,8 @@ class TIA : public AbstractTIA {
|
|||
|
||||
private:
|
||||
|
||||
void onFrameComplete();
|
||||
|
||||
void delayedWrite(uInt8 address, uInt8 value);
|
||||
|
||||
private:
|
||||
|
@ -129,6 +132,8 @@ class TIA : public AbstractTIA {
|
|||
|
||||
DelayQueue myDelayQueue;
|
||||
|
||||
FrameManager myFrameManager;
|
||||
|
||||
private:
|
||||
|
||||
TIA() = delete;
|
||||
|
|
|
@ -3,7 +3,8 @@ MODULE := src/emucore/tia/core_6502ts
|
|||
MODULE_OBJS := \
|
||||
src/emucore/tia/core_6502ts/TIA.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 += \
|
||||
|
|
Loading…
Reference in New Issue