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;
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ uInt32 FrameManager::currentLine() const
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void FrameManager::setTvMode(FrameManager::TvMode mode)
|
||||
void FrameManager::setTvMode(TvMode mode)
|
||||
{
|
||||
if (mode == myMode) return;
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <functional>
|
||||
|
||||
#include "Serializable.hxx"
|
||||
#include "Types.hxx"
|
||||
#include "bspf.hxx"
|
||||
|
||||
namespace TIA6502tsCore {
|
||||
|
@ -31,10 +32,6 @@ class FrameManager : public Serializable
|
|||
{
|
||||
public:
|
||||
|
||||
enum TvMode {
|
||||
pal, ntsc
|
||||
};
|
||||
|
||||
using callback = std::function<void()>;
|
||||
|
||||
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 "M6502.hxx"
|
||||
#include "Console.hxx"
|
||||
#include "Types.hxx"
|
||||
|
||||
enum CollisionMask: uInt32 {
|
||||
player0 = 0b0111110000000000,
|
||||
|
@ -65,6 +66,7 @@ TIA::TIA(Console& console, Sound& sound, Settings& settings)
|
|||
myFrameManager.setHandlers(
|
||||
[this] () {
|
||||
myCurrentFrameBuffer.swap(myPreviousFrameBuffer);
|
||||
updatePaddles();
|
||||
},
|
||||
[this] () {
|
||||
mySystem->m6502().stop();
|
||||
|
@ -108,6 +110,10 @@ void TIA::reset()
|
|||
myInput0.reset();
|
||||
myInput1.reset();
|
||||
|
||||
myTimestamp = 0;
|
||||
for (PaddleReader& paddleReader : myPaddleReaders)
|
||||
paddleReader.reset(myTimestamp);
|
||||
|
||||
mySound.reset();
|
||||
myDelayQueue.reset();
|
||||
myFrameManager.reset();
|
||||
|
@ -267,6 +273,22 @@ uInt8 TIA::peek(uInt16 address)
|
|||
result = (myCollisionMask & CollisionMask::ball & CollisionMask::playfield) ? 0x80 : 0;
|
||||
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:
|
||||
result = myInput0.inpt(!myConsole.leftController().read(Controller::Six));
|
||||
break;
|
||||
|
@ -308,6 +330,10 @@ bool TIA::poke(uInt16 address, uInt8 value)
|
|||
myInput1.vblank(value);
|
||||
|
||||
myFrameManager.setVblank(value & 0x02);
|
||||
|
||||
for (PaddleReader& paddleReader : myPaddleReaders)
|
||||
paddleReader.vblank(value, myTimestamp);
|
||||
|
||||
break;
|
||||
|
||||
case AUDV0:
|
||||
|
@ -582,7 +608,7 @@ void TIA::enableColorLoss(bool enabled)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
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();
|
||||
|
||||
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
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "Player.hxx"
|
||||
#include "Ball.hxx"
|
||||
#include "LatchedInput.hxx"
|
||||
#include "PaddleReader.hxx"
|
||||
|
||||
class Console;
|
||||
|
||||
|
@ -176,6 +177,8 @@ class TIA : public AbstractTIA
|
|||
|
||||
void delayedWrite(uInt8 address, uInt8 value);
|
||||
|
||||
void updatePaddles();
|
||||
|
||||
private:
|
||||
|
||||
Console& myConsole;
|
||||
|
@ -209,6 +212,8 @@ class TIA : public AbstractTIA
|
|||
|
||||
uInt8 myColorBk;
|
||||
|
||||
double myTimestamp;
|
||||
|
||||
BytePtr myCurrentFrameBuffer;
|
||||
BytePtr myPreviousFrameBuffer;
|
||||
|
||||
|
@ -218,6 +223,7 @@ class TIA : public AbstractTIA
|
|||
Player myPlayer0;
|
||||
Player myPlayer1;
|
||||
Ball myBall;
|
||||
PaddleReader myPaddleReaders[4];
|
||||
|
||||
LatchedInput myInput0;
|
||||
LatchedInput myInput1;
|
||||
|
|
|
@ -10,7 +10,8 @@ MODULE_OBJS := \
|
|||
src/emucore/tia/core_6502ts/Missile.o \
|
||||
src/emucore/tia/core_6502ts/Player.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 += \
|
||||
|
|
Loading…
Reference in New Issue