mirror of https://github.com/stella-emu/stella.git
Paddles / analog input.
This commit is contained in:
parent
3e4b975489
commit
042dc72e66
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 += \
|
||||||
|
|
Loading…
Reference in New Issue