This commit is contained in:
Christian Speckner 2016-11-13 22:56:58 +01:00
parent ea6abb0fe6
commit b6a2e266aa
4 changed files with 392 additions and 392 deletions

View File

@ -21,40 +21,40 @@
namespace TIA6502tsCore { namespace TIA6502tsCore {
DelayQueue::DelayQueue(uInt8 length, uInt8 size) DelayQueue::DelayQueue(uInt8 length, uInt8 size)
: myIndex(0) : myIndex(0)
{ {
myMembers.reserve(length); myMembers.reserve(length);
for (uInt16 i = 0; i < length; i++) for (uInt16 i = 0; i < length; i++)
myMembers.emplace_back(size); myMembers.emplace_back(size);
for (uInt8& i : myIndices) for (uInt8& i : myIndices)
i = 0xFF; i = 0xFF;
} }
void DelayQueue::push(uInt8 address, uInt8 value, uInt8 delay) void DelayQueue::push(uInt8 address, uInt8 value, uInt8 delay)
{ {
uInt8 length = myMembers.size(); uInt8 length = myMembers.size();
if (delay >= length) if (delay >= length)
throw new runtime_error("delay exceeds queue length"); throw new runtime_error("delay exceeds queue length");
uInt8 currentIndex = myIndices[address]; uInt8 currentIndex = myIndices[address];
if (currentIndex < 0xFF) if (currentIndex < 0xFF)
myMembers.at(currentIndex).remove(address); myMembers.at(currentIndex).remove(address);
uInt8 index = (myIndex + delay) % length; uInt8 index = (myIndex + delay) % length;
myMembers.at(index).push(address, value); myMembers.at(index).push(address, value);
myIndices[address] = index; myIndices[address] = index;
} }
void DelayQueue::reset() void DelayQueue::reset()
{ {
for (DelayQueueMember& member : myMembers) for (DelayQueueMember& member : myMembers)
member.clear(); member.clear();
} }
} // namespace TIA6502tsCore } // namespace TIA6502tsCore

View File

@ -1,8 +1,8 @@
//============================================================================ //============================================================================
// //
// SSSS tt lll lll // SSSS tt lll lll
// SS SS tt ll ll // SS SS tt ll ll
// SS tttttt eeee ll ll aaaa // SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa // SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa // SS SS tt ee ll ll aa aa
@ -21,46 +21,46 @@
namespace TIA6502tsCore { namespace TIA6502tsCore {
DelayQueueMember::DelayQueueMember(uInt8 capacity) DelayQueueMember::DelayQueueMember(uInt8 capacity)
: myEntries(capacity), : myEntries(capacity),
mySize(0) mySize(0)
{} {}
void DelayQueueMember::push(uInt8 address, uInt8 value) void DelayQueueMember::push(uInt8 address, uInt8 value)
{ {
Entry& entry = myEntries.at(mySize++); Entry& entry = myEntries.at(mySize++);
entry.address = address; entry.address = address;
entry.value = value; entry.value = value;
}
void DelayQueueMember::remove(uInt8 address)
{
size_t index;
for (index = 0; index < mySize; index++) {
if (myEntries.at(index).address == address) break;
} }
void DelayQueueMember::remove(uInt8 address) if (index < mySize) {
{ myEntries.at(index) = myEntries.at(mySize - 1);
size_t index; mySize--;
for (index = 0; index < mySize; index++) {
if (myEntries.at(index).address == address) break;
}
if (index < mySize) {
myEntries.at(index) = myEntries.at(mySize - 1);
mySize--;
}
} }
}
vector<DelayQueueMember::Entry>::const_iterator DelayQueueMember::begin() const vector<DelayQueueMember::Entry>::const_iterator DelayQueueMember::begin() const
{ {
return myEntries.begin(); return myEntries.begin();
} }
vector<DelayQueueMember::Entry>::const_iterator DelayQueueMember::end() const vector<DelayQueueMember::Entry>::const_iterator DelayQueueMember::end() const
{ {
return myEntries.end(); return myEntries.end();
} }
void DelayQueueMember::clear() void DelayQueueMember::clear()
{ {
mySize = 0; mySize = 0;
} }
} // namespace TIA6502tsCore } // namespace TIA6502tsCore

View File

@ -39,182 +39,182 @@ static constexpr uInt32
namespace TIA6502tsCore { namespace TIA6502tsCore {
FrameManager::FrameManager() FrameManager::FrameManager()
{ {
reset(); reset();
} }
void FrameManager::setOnFrameCompleteHandler(FrameManager::frameCompletionHandler handler) void FrameManager::setOnFrameCompleteHandler(FrameManager::frameCompletionHandler handler)
{ {
myOnFrameComplete = handler; myOnFrameComplete = handler;
} }
void FrameManager::reset() void FrameManager::reset()
{ {
setTvMode(TvMode::ntsc); setTvMode(TvMode::ntsc);
setState(State::waitForVsyncStart); setState(State::waitForVsyncStart);
myLineInState = 0; myLineInState = 0;
myLinesWithoutVsync = 0; myLinesWithoutVsync = 0;
myWaitForVsync = true; myWaitForVsync = true;
myVsync = false; myVsync = false;
myVblank = false; myVblank = false;
} }
void FrameManager::nextLine() void FrameManager::nextLine()
{ {
myCurrentFrameTotalLines++; myCurrentFrameTotalLines++;
myLineInState++; myLineInState++;
switch (myState) { switch (myState) {
case State::waitForVsyncStart: case State::waitForVsyncStart:
case State::waitForVsyncEnd: case State::waitForVsyncEnd:
if (myLinesWithoutVsync > myMaxLinesWithoutVsync) { if (myLinesWithoutVsync > myMaxLinesWithoutVsync) {
myWaitForVsync = false; myWaitForVsync = false;
setState(State::waitForFrameStart); 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; break;
case State::waitForFrameStart: case State::frame:
if (myWaitForVsync) { if (myLineInState >= myFrameLines + Metrics::visibleOverscan) {
if (myLineInState >= (myVblank ? myVblankLines : myVblankLines - Metrics::maxUnderscan)) finalizeFrame();
setState(State::frame); }
} else {
if (!myVblank) {
setState(State::frame);
}
}
break; break;
case State::frame: case State::overscan:
if (myLineInState >= myFrameLines + Metrics::visibleOverscan) { if (myLineInState >= myOverscanLines - Metrics::visibleOverscan) {
finalizeFrame(); setState(myWaitForVsync ? State::waitForVsyncStart : State::waitForFrameStart);
} }
break; break;
case State::overscan: default:
if (myLineInState >= myOverscanLines - Metrics::visibleOverscan) { throw runtime_error("frame manager: invalid state");
setState(myWaitForVsync ? State::waitForVsyncStart : State::waitForFrameStart); }
} }
break; void FrameManager::setVblank(bool vblank)
{
myVblank = vblank;
}
default: void FrameManager::setVsync(bool vsync)
throw runtime_error("frame manager: invalid state"); {
} 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");
} }
void FrameManager::setVblank(bool vblank) myFrameLines = Metrics::vsync + myVblankLines + myKernelLines + myOverscanLines;
{ myMaxLinesWithoutVsync = myFrameLines * Metrics::maxFramesWithoutVsync;
myVblank = vblank; }
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);
} }
void FrameManager::setVsync(bool vsync) if (myOnFrameComplete) {
{ myOnFrameComplete();
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 { myCurrentFrameTotalLines = 0;
return myState == State::frame; setState(State::overscan);
} }
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 } // namespace TIA6502tsCore

View File

@ -22,216 +22,216 @@
namespace TIA6502tsCore { namespace TIA6502tsCore {
// TODO: stub // TODO: stub
TIA::TIA(Console& console, Sound& sound, Settings& settings) TIA::TIA(Console& console, Sound& sound, Settings& settings)
: myConsole(console), : myConsole(console),
mySound(sound), mySound(sound),
mySettings(settings), mySettings(settings),
myDelayQueue(10, 20) myDelayQueue(10, 20)
{ {
myFrameManager.setOnFrameCompleteHandler( myFrameManager.setOnFrameCompleteHandler(
[this] () {onFrameComplete();} [this] () {onFrameComplete();}
); );
reset(); reset();
} }
// TODO: stub // TODO: stub
void TIA::reset() void TIA::reset()
{ {
myDelayQueue.reset(); myDelayQueue.reset();
} }
// TODO: stub // TODO: stub
void TIA::systemCyclesReset() void TIA::systemCyclesReset()
{} {}
// TODO: stub // TODO: stub
void TIA::install(System& system) void TIA::install(System& system)
{} {}
// TODO: stub // TODO: stub
bool TIA::save(Serializer& out) const bool TIA::save(Serializer& out) const
{ {
return true; return true;
} }
// TODO: stub // TODO: stub
bool TIA::load(Serializer& in) bool TIA::load(Serializer& in)
{ {
return true; return true;
} }
// TODO: stub // TODO: stub
uInt8 TIA::peek(uInt16 address) uInt8 TIA::peek(uInt16 address)
{ {
return 0; return 0;
} }
// TODO: stub // TODO: stub
bool TIA::poke(uInt16 address, uInt8 value) bool TIA::poke(uInt16 address, uInt8 value)
{ {
return false; return false;
} }
// TODO: stub // TODO: stub
void TIA::installDelegate(System& system, Device& device) void TIA::installDelegate(System& system, Device& device)
{} {}
// TODO: stub // TODO: stub
void TIA::frameReset() void TIA::frameReset()
{} {}
// TODO: stub // TODO: stub
bool TIA::saveDisplay(Serializer& out) const bool TIA::saveDisplay(Serializer& out) const
{ {
return true; return true;
} }
// TODO: stub // TODO: stub
bool TIA::loadDisplay(Serializer& in) bool TIA::loadDisplay(Serializer& in)
{ {
return true; return true;
} }
// TODO: stub // TODO: stub
void TIA::update() void TIA::update()
{} {}
// TODO: stub // TODO: stub
uInt8* TIA::currentFrameBuffer() const uInt8* TIA::currentFrameBuffer() const
{ {
return 0; return 0;
} }
// TODO: stub // TODO: stub
uInt8* TIA::previousFrameBuffer() const uInt8* TIA::previousFrameBuffer() const
{ {
return 0; return 0;
} }
// TODO: stub // TODO: stub
uInt32 TIA::height() const uInt32 TIA::height() const
{ {
return 0; return 0;
} }
// TODO: stub // TODO: stub
uInt32 TIA::ystart() const uInt32 TIA::ystart() const
{ {
return 0; return 0;
} }
// TODO: stub // TODO: stub
void TIA::setHeight(uInt32 height) void TIA::setHeight(uInt32 height)
{} {}
// TODO: stub // TODO: stub
void TIA::setYStart(uInt32 ystart) void TIA::setYStart(uInt32 ystart)
{} {}
// TODO: stub // TODO: stub
void TIA::enableAutoFrame(bool enabled) void TIA::enableAutoFrame(bool enabled)
{} {}
// TODO: stub // TODO: stub
void TIA::enableColorLoss(bool enabled) void TIA::enableColorLoss(bool enabled)
{} {}
// TODO: stub // TODO: stub
bool TIA::isPAL() const bool TIA::isPAL() const
{ {
return false; return false;
} }
// TODO: stub // TODO: stub
uInt32 TIA::clocksThisLine() const uInt32 TIA::clocksThisLine() const
{ {
return 0; return 0;
} }
// TODO: stub // TODO: stub
uInt32 TIA::scanlines() const uInt32 TIA::scanlines() const
{ {
return 0; return 0;
} }
// TODO: stub // TODO: stub
bool TIA::partialFrame() const bool TIA::partialFrame() const
{ {
return false; return false;
} }
// TODO: stub // TODO: stub
uInt32 TIA::startScanline() const uInt32 TIA::startScanline() const
{ {
return 0; return 0;
} }
// TODO: stub // TODO: stub
bool TIA::scanlinePos(uInt16& x, uInt16& y) const bool TIA::scanlinePos(uInt16& x, uInt16& y) const
{ {
return 0; return 0;
} }
// TODO: stub // TODO: stub
bool TIA::toggleBit(TIABit b, uInt8 mode) bool TIA::toggleBit(TIABit b, uInt8 mode)
{ {
return false; return false;
} }
// TODO: stub // TODO: stub
bool TIA::toggleBits() bool TIA::toggleBits()
{ {
return false; return false;
} }
// TODO: stub // TODO: stub
bool TIA::toggleCollision(TIABit b, uInt8 mode) bool TIA::toggleCollision(TIABit b, uInt8 mode)
{ {
return false; return false;
} }
// TODO: stub // TODO: stub
bool TIA::toggleCollisions() bool TIA::toggleCollisions()
{ {
return false; return false;
} }
// TODO: stub // TODO: stub
bool TIA::toggleHMOVEBlank() bool TIA::toggleHMOVEBlank()
{ {
return false; return false;
} }
// TODO: stub // TODO: stub
bool TIA::toggleFixedColors(uInt8 mode) bool TIA::toggleFixedColors(uInt8 mode)
{ {
return false; return false;
} }
// TODO: stub // TODO: stub
bool TIA::driveUnusedPinsRandom(uInt8 mode) bool TIA::driveUnusedPinsRandom(uInt8 mode)
{ {
return false; return false;
} }
// TODO: stub // TODO: stub
bool TIA::toggleJitter(uInt8 mode) bool TIA::toggleJitter(uInt8 mode)
{ {
return false; return false;
} }
// TODO: stub // TODO: stub
void TIA::setJitterRecoveryFactor(Int32 f) void TIA::setJitterRecoveryFactor(Int32 f)
{} {}
// TODO: stub // TODO: stub
void TIA::onFrameComplete() void TIA::onFrameComplete()
{} {}
// TODO: stub // TODO: stub
void TIA::delayedWrite(uInt8 address, uInt8 value) void TIA::delayedWrite(uInt8 address, uInt8 value)
{} {}
} // namespace TIA6502tsCore } // namespace TIA6502tsCore