Paddles / analog input.

This commit is contained in:
Christian Speckner 2016-11-28 12:54:46 +01:00
parent 3e4b975489
commit 042dc72e66
7 changed files with 250 additions and 8 deletions

View File

@ -159,7 +159,7 @@ bool FrameManager::isRendering() const
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameManager::TvMode FrameManager::tvMode() const TvMode FrameManager::tvMode() const
{ {
return myMode; return myMode;
} }
@ -183,7 +183,7 @@ uInt32 FrameManager::currentLine() const
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameManager::setTvMode(FrameManager::TvMode mode) void FrameManager::setTvMode(TvMode mode)
{ {
if (mode == myMode) return; if (mode == myMode) return;

View File

@ -23,6 +23,7 @@
#include <functional> #include <functional>
#include "Serializable.hxx" #include "Serializable.hxx"
#include "Types.hxx"
#include "bspf.hxx" #include "bspf.hxx"
namespace TIA6502tsCore { namespace TIA6502tsCore {
@ -31,10 +32,6 @@ class FrameManager : public Serializable
{ {
public: public:
enum TvMode {
pal, ntsc
};
using callback = std::function<void()>; using callback = std::function<void()>;
public: public:

View File

@ -0,0 +1,120 @@
//============================================================================
//
// 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 <cmath>
#include "PaddleReader.hxx"
static double expApprox(double x)
{
double x2 = x * x / 2,
x3 = x2 * x / 3,
x4 = x3 * x / 4;
return 1 + x + x2 + x3 + x4;
}
static constexpr double
C = 68e-9,
RPOT = 1e6,
R0 = 1.8e3,
USUPP = 5;
static constexpr double TRIPPOINT_LINES = 380;
namespace TIA6502tsCore {
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PaddleReader::PaddleReader()
{
reset(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PaddleReader::reset(double timestamp)
{
myU = 0;
myIsDumped = false;
myValue = 0;
myTimestamp = timestamp;
setTvMode(TvMode::ntsc);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PaddleReader::vblank(uInt8 value, double timestamp)
{
bool oldIsDumped = myIsDumped;
if (value & 0x80) {
myIsDumped = true;
myU = 0;
myTimestamp = timestamp;
} else if (oldIsDumped) {
myIsDumped = false;
myTimestamp = timestamp;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 PaddleReader::inpt(double timestamp)
{
updateCharge(timestamp);
bool state = myIsDumped ? false : myU > myUThresh;
return state ? 0x80 : 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PaddleReader::update(double value, double timestamp, TvMode tvMode)
{
if (tvMode != myTvMode) {
setTvMode(tvMode);
}
if (value != myValue) {
myValue = value;
updateCharge(timestamp);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PaddleReader::setTvMode(TvMode mode)
{
myTvMode = mode;
myClockFreq = myTvMode == TvMode::ntsc ? 60 * 228 * 262 : 50 * 228 * 312;
myUThresh = USUPP * (1. - exp(-TRIPPOINT_LINES * 228 / myClockFreq / (RPOT + R0) / C));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PaddleReader::updateCharge(double timestamp)
{
if (myIsDumped) return;
myU = USUPP * (1 - (1 - myU / USUPP) *
expApprox(-(timestamp - myTimestamp) / (myValue * RPOT + R0) / C / myClockFreq));
myTimestamp = timestamp;
}
} // namespace TIA6502tsCore

View File

@ -0,0 +1,73 @@
//============================================================================
//
// 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_PADDLE_READER
#define TIA_6502TS_CORE_PADDLE_READER
#include "bspf.hxx"
#include "Types.hxx"
namespace TIA6502tsCore {
class PaddleReader
{
public:
PaddleReader();
public:
void reset(double timestamp);
void vblank(uInt8 value, double timestamp);
uInt8 inpt(double timestamp);
void update(double value, double timestamp, TvMode tvMode);
private:
void setTvMode(TvMode mode);
void updateCharge(double timestamp);
private:
double myUThresh;
double myU;
double myValue;
double myTimestamp;
TvMode myTvMode;
double myClockFreq;
bool myIsDumped;
private:
PaddleReader(const PaddleReader&) = delete;
PaddleReader(PaddleReader&&) = delete;
PaddleReader& operator=(const PaddleReader&) = delete;
PaddleReader& operator=(PaddleReader&&) = delete;
};
} // namespace TIA6502tsCore
#endif // TIA_6502TS_CORE_PADDLE_READER

View File

@ -21,6 +21,7 @@
#include "TIATypes.hxx" #include "TIATypes.hxx"
#include "M6502.hxx" #include "M6502.hxx"
#include "Console.hxx" #include "Console.hxx"
#include "Types.hxx"
enum CollisionMask: uInt32 { enum CollisionMask: uInt32 {
player0 = 0b0111110000000000, player0 = 0b0111110000000000,
@ -65,6 +66,7 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings)
myFrameManager.setHandlers( myFrameManager.setHandlers(
[this] () { [this] () {
myCurrentFrameBuffer.swap(myPreviousFrameBuffer); myCurrentFrameBuffer.swap(myPreviousFrameBuffer);
updatePaddles();
}, },
[this] () { [this] () {
mySystem->m6502().stop(); mySystem->m6502().stop();
@ -108,6 +110,10 @@ void TIA::reset()
myInput0.reset(); myInput0.reset();
myInput1.reset(); myInput1.reset();
myTimestamp = 0;
for (PaddleReader& paddleReader : myPaddleReaders)
paddleReader.reset(myTimestamp);
mySound.reset(); mySound.reset();
myDelayQueue.reset(); myDelayQueue.reset();
myFrameManager.reset(); myFrameManager.reset();
@ -267,6 +273,22 @@ uInt8 TIA::peek(uInt16 address)
result = (myCollisionMask & CollisionMask::ball & CollisionMask::playfield) ? 0x80 : 0; result = (myCollisionMask & CollisionMask::ball & CollisionMask::playfield) ? 0x80 : 0;
break; break;
case INPT0:
result = myPaddleReaders[0].inpt(myTimestamp);
break;
case INPT1:
result = myPaddleReaders[1].inpt(myTimestamp);
break;
case INPT2:
result = myPaddleReaders[2].inpt(myTimestamp);
break;
case INPT3:
result = myPaddleReaders[3].inpt(myTimestamp);
break;
case INPT4: case INPT4:
result = myInput0.inpt(!myConsole.leftController().read(Controller::Six)); result = myInput0.inpt(!myConsole.leftController().read(Controller::Six));
break; break;
@ -308,6 +330,10 @@ bool TIA::poke(uInt16 address, uInt8 value)
myInput1.vblank(value); myInput1.vblank(value);
myFrameManager.setVblank(value & 0x02); myFrameManager.setVblank(value & 0x02);
for (PaddleReader& paddleReader : myPaddleReaders)
paddleReader.vblank(value, myTimestamp);
break; break;
case AUDV0: case AUDV0:
@ -582,7 +608,7 @@ void TIA::enableColorLoss(bool enabled)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool TIA::isPAL() const bool TIA::isPAL() const
{ {
return myFrameManager.tvMode() == FrameManager::TvMode::pal; return myFrameManager.tvMode() == TvMode::pal;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -721,6 +747,8 @@ void TIA::cycle(uInt32 colorClocks)
tickHframe(); tickHframe();
if (myCollisionUpdateRequired) updateCollision(); if (myCollisionUpdateRequired) updateCollision();
myTimestamp++;
} }
} }
@ -985,4 +1013,21 @@ void TIA::delayedWrite(uInt8 address, uInt8 value)
} }
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::updatePaddles()
{
static constexpr double MAX_RESISTANCE = 1400000;
TvMode tvMode = myFrameManager.tvMode();
Int32 resistances[] = {
myConsole.leftController().read(Controller::Nine),
myConsole.leftController().read(Controller::Five),
myConsole.rightController().read(Controller::Nine),
myConsole.rightController().read(Controller::Five),
};
for (uInt8 i = 0; i < 4; i++)
myPaddleReaders[i].update(double(resistances[i]) / MAX_RESISTANCE, myTimestamp, tvMode);
}
} // namespace TIA6502tsCore } // namespace TIA6502tsCore

View File

@ -32,6 +32,7 @@
#include "Player.hxx" #include "Player.hxx"
#include "Ball.hxx" #include "Ball.hxx"
#include "LatchedInput.hxx" #include "LatchedInput.hxx"
#include "PaddleReader.hxx"
class Console; class Console;
@ -176,6 +177,8 @@ class TIA : public AbstractTIA
void delayedWrite(uInt8 address, uInt8 value); void delayedWrite(uInt8 address, uInt8 value);
void updatePaddles();
private: private:
Console& myConsole; Console& myConsole;
@ -209,6 +212,8 @@ class TIA : public AbstractTIA
uInt8 myColorBk; uInt8 myColorBk;
double myTimestamp;
BytePtr myCurrentFrameBuffer; BytePtr myCurrentFrameBuffer;
BytePtr myPreviousFrameBuffer; BytePtr myPreviousFrameBuffer;
@ -218,6 +223,7 @@ class TIA : public AbstractTIA
Player myPlayer0; Player myPlayer0;
Player myPlayer1; Player myPlayer1;
Ball myBall; Ball myBall;
PaddleReader myPaddleReaders[4];
LatchedInput myInput0; LatchedInput myInput0;
LatchedInput myInput1; LatchedInput myInput1;

View File

@ -10,7 +10,8 @@ MODULE_OBJS := \
src/emucore/tia/core_6502ts/Missile.o \ src/emucore/tia/core_6502ts/Missile.o \
src/emucore/tia/core_6502ts/Player.o \ src/emucore/tia/core_6502ts/Player.o \
src/emucore/tia/core_6502ts/Ball.o \ src/emucore/tia/core_6502ts/Ball.o \
src/emucore/tia/core_6502ts/LatchedInput.o src/emucore/tia/core_6502ts/LatchedInput.o \
src/emucore/tia/core_6502ts/PaddleReader.o
MODULE_DIRS += \ MODULE_DIRS += \