From a5cb5172802a1f64d82cb168ff7081254dcd74e1 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Fri, 2 Apr 2021 00:15:13 +0200 Subject: [PATCH] Adjust paddle parameters, improve keyboard controller emulation, emulate cap discharge, --- src/emucore/Keyboard.cxx | 72 +++++++++++++++++--------------- src/emucore/Keyboard.hxx | 12 +++++- src/emucore/Paddles.hxx | 2 +- src/emucore/tia/PaddleReader.cxx | 23 ++++------ src/emucore/tia/PaddleReader.hxx | 2 +- 5 files changed, 60 insertions(+), 51 deletions(-) diff --git a/src/emucore/Keyboard.cxx b/src/emucore/Keyboard.cxx index b439b3b21..83eef8089 100644 --- a/src/emucore/Keyboard.cxx +++ b/src/emucore/Keyboard.cxx @@ -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)); } diff --git a/src/emucore/Keyboard.hxx b/src/emucore/Keyboard.hxx index 6791c960f..ca1442194 100644 --- a/src/emucore/Keyboard.hxx +++ b/src/emucore/Keyboard.hxx @@ -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 diff --git a/src/emucore/Paddles.hxx b/src/emucore/Paddles.hxx index f1e645c98..62d7bd04c 100644 --- a/src/emucore/Paddles.hxx +++ b/src/emucore/Paddles.hxx @@ -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 diff --git a/src/emucore/tia/PaddleReader.cxx b/src/emucore/tia/PaddleReader.cxx index 0121e9b36..2e37413a0 100644 --- a/src/emucore/tia/PaddleReader.cxx +++ b/src/emucore/tia/PaddleReader.cxx @@ -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(timestamp - myTimestamp) / (myValue * RPOT + R0) / C / myClockFreq)); + else + myU *= exp(-static_cast(timestamp - myTimestamp) / R0 / C / myClockFreq); myTimestamp = timestamp; } diff --git a/src/emucore/tia/PaddleReader.hxx b/src/emucore/tia/PaddleReader.hxx index 27fb1a396..18b2468db 100644 --- a/src/emucore/tia/PaddleReader.hxx +++ b/src/emucore/tia/PaddleReader.hxx @@ -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;