mirror of https://github.com/stella-emu/stella.git
Adjust paddle parameters, improve keyboard controller emulation, emulate cap discharge,
This commit is contained in:
parent
bdd7035fef
commit
3902778b12
|
@ -54,44 +54,50 @@ Keyboard::Keyboard(Jack jack, const Event& event, const System& system)
|
|||
}
|
||||
}
|
||||
|
||||
Keyboard::ColumnState Keyboard::processColumn(const Event::Type buttons[]) {
|
||||
constexpr DigitalPin signals[] =
|
||||
{DigitalPin::One, DigitalPin::Two, DigitalPin::Three, DigitalPin::Four};
|
||||
|
||||
for (uInt8 i = 0; i < 4; i++)
|
||||
if (myEvent.get(buttons[i]) && !getPin(signals[i])) return ColumnState::gnd;
|
||||
|
||||
for (uInt8 i = 0; i < 4; i++)
|
||||
if (myEvent.get(buttons[i]) && getPin(signals[i])) return ColumnState::vcc;
|
||||
|
||||
return ColumnState::notConneccted;
|
||||
}
|
||||
|
||||
Int32 Keyboard::columnStateToAnalogSignal(ColumnState state) const {
|
||||
switch (state) {
|
||||
case ColumnState::gnd:
|
||||
return MAX_RESISTANCE;
|
||||
|
||||
case ColumnState::vcc:
|
||||
return 0;
|
||||
|
||||
case ColumnState::notConneccted:
|
||||
return INTERNAL_RESISTANCE;
|
||||
|
||||
default:
|
||||
throw runtime_error("unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void Keyboard::write(DigitalPin pin, bool value)
|
||||
{
|
||||
setPin(pin, value);
|
||||
|
||||
// Set defaults
|
||||
setPin(DigitalPin::Six, true);
|
||||
Int32 resistanceFive = MIN_RESISTANCE;
|
||||
Int32 resistanceNine = MIN_RESISTANCE;
|
||||
const Event::Type col0[] = {myOneEvent, myFourEvent, mySevenEvent, myStarEvent};
|
||||
const Event::Type col1[] = {myTwoEvent, myFiveEvent, myEightEvent, myZeroEvent};
|
||||
const Event::Type col2[] = {myThreeEvent, mySixEvent, myNineEvent, myPoundEvent};
|
||||
|
||||
// Now scan the rows and columns
|
||||
if(!getPin(DigitalPin::Four))
|
||||
{
|
||||
setPin(DigitalPin::Six, myEvent.get(myPoundEvent) == 0);
|
||||
if(myEvent.get(myZeroEvent) != 0) resistanceFive = MAX_RESISTANCE;
|
||||
if(myEvent.get(myStarEvent) != 0) resistanceNine = MAX_RESISTANCE;
|
||||
}
|
||||
if(!getPin(DigitalPin::Three))
|
||||
{
|
||||
setPin(DigitalPin::Six, myEvent.get(myNineEvent) == 0);
|
||||
if(myEvent.get(myEightEvent) != 0) resistanceFive = MAX_RESISTANCE;
|
||||
if(myEvent.get(mySevenEvent) != 0) resistanceNine = MAX_RESISTANCE;
|
||||
}
|
||||
if(!getPin(DigitalPin::Two))
|
||||
{
|
||||
setPin(DigitalPin::Six, myEvent.get(mySixEvent) == 0);
|
||||
if(myEvent.get(myFiveEvent) != 0) resistanceFive = MAX_RESISTANCE;
|
||||
if(myEvent.get(myFourEvent) != 0) resistanceNine = MAX_RESISTANCE;
|
||||
}
|
||||
if(!getPin(DigitalPin::One))
|
||||
{
|
||||
setPin(DigitalPin::Six, myEvent.get(myThreeEvent) == 0);
|
||||
if(myEvent.get(myTwoEvent) != 0) resistanceFive = MAX_RESISTANCE;
|
||||
if(myEvent.get(myOneEvent) != 0) resistanceNine = MAX_RESISTANCE;
|
||||
}
|
||||
ColumnState stateCol0 = processColumn(col0);
|
||||
ColumnState stateCol1 = processColumn(col1);
|
||||
ColumnState stateCol2 = processColumn(col2);
|
||||
|
||||
if(resistanceFive != read(AnalogPin::Five))
|
||||
setPin(AnalogPin::Five, resistanceFive);
|
||||
if(resistanceNine != read(AnalogPin::Nine))
|
||||
setPin(AnalogPin::Nine, resistanceNine);
|
||||
setPin(DigitalPin::Six, stateCol2 == ColumnState::gnd ? 0 : 1);
|
||||
setPin(AnalogPin::Five, columnStateToAnalogSignal(stateCol1));
|
||||
setPin(AnalogPin::Nine, columnStateToAnalogSignal(stateCol0));
|
||||
}
|
||||
|
|
|
@ -62,6 +62,16 @@ class Keyboard : public Controller
|
|||
*/
|
||||
string name() const override { return "Keyboard"; }
|
||||
|
||||
private:
|
||||
enum class ColumnState {
|
||||
vcc, gnd, notConneccted
|
||||
};
|
||||
|
||||
private:
|
||||
ColumnState processColumn(const Event::Type buttons[]);
|
||||
|
||||
Int32 columnStateToAnalogSignal(ColumnState state) const;
|
||||
|
||||
private:
|
||||
// Pre-compute the events we care about based on given port
|
||||
// This will eliminate test for left or right port in update()
|
||||
|
@ -70,7 +80,7 @@ class Keyboard : public Controller
|
|||
mySevenEvent, myEightEvent, myNineEvent,
|
||||
myStarEvent, myZeroEvent, myPoundEvent;
|
||||
|
||||
static constexpr Int32 MIN_RESISTANCE = 5600;
|
||||
static constexpr Int32 INTERNAL_RESISTANCE = 4700;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
|
|
|
@ -162,7 +162,7 @@ class Paddles : public Controller
|
|||
*/
|
||||
static void setDigitalPaddleRange(int range);
|
||||
|
||||
static constexpr double MAX_RESISTANCE = 1400000.0;
|
||||
static constexpr double MAX_RESISTANCE = 1000000.0;
|
||||
|
||||
private:
|
||||
// Range of values over which digital and mouse movement is scaled
|
||||
|
|
|
@ -40,16 +40,17 @@ void PaddleReader::reset(uInt64 timestamp)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PaddleReader::vblank(uInt8 value, uInt64 timestamp)
|
||||
{
|
||||
updateCharge(timestamp);
|
||||
|
||||
bool oldIsDumped = myIsDumped;
|
||||
|
||||
if (value & 0x80) {
|
||||
myIsDumped = true;
|
||||
myU = 0;
|
||||
myTimestamp = timestamp;
|
||||
} else if (oldIsDumped) {
|
||||
myIsDumped = false;
|
||||
myTimestamp = timestamp;
|
||||
}
|
||||
|
||||
myTimestamp = timestamp;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -72,15 +73,7 @@ void PaddleReader::update(double value, uInt64 timestamp, ConsoleTiming consoleT
|
|||
if (value != myValue) {
|
||||
myValue = value;
|
||||
|
||||
if (myValue < 0) {
|
||||
// value < 0 signifies either maximum resistance OR analog input connected to
|
||||
// ground (keyboard controllers). As we have no way to tell these apart we just
|
||||
// assume ground and discharge.
|
||||
myU = 0;
|
||||
myTimestamp = timestamp;
|
||||
} else {
|
||||
updateCharge(timestamp);
|
||||
}
|
||||
updateCharge(timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,11 +89,11 @@ void PaddleReader::setConsoleTiming(ConsoleTiming consoleTiming)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PaddleReader::updateCharge(uInt64 timestamp)
|
||||
{
|
||||
if (myIsDumped) return;
|
||||
|
||||
if (myValue >= 0)
|
||||
if (myValue >= 0 && !myIsDumped)
|
||||
myU = USUPP * (1 - (1 - myU / USUPP) *
|
||||
exp(-static_cast<double>(timestamp - myTimestamp) / (myValue * RPOT + R0) / C / myClockFreq));
|
||||
else
|
||||
myU *= exp(-static_cast<double>(timestamp - myTimestamp) / R0 / C / myClockFreq);
|
||||
|
||||
myTimestamp = timestamp;
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ class PaddleReader : public Serializable
|
|||
bool myIsDumped{false};
|
||||
|
||||
static constexpr double
|
||||
R0 = 1.5e3,
|
||||
R0 = 1.8e3,
|
||||
C = 68e-9,
|
||||
RPOT = 1e6,
|
||||
USUPP = 5;
|
||||
|
|
Loading…
Reference in New Issue