1 | //============================================================================ |
---|---|
2 | // |
3 | // SSSS tt lll lll |
4 | // SS SS tt ll ll |
5 | // SS tttttt eeee ll ll aaaa |
6 | // SSSS tt ee ee ll ll aa |
7 | // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" |
8 | // SS SS tt ee ll ll aa aa |
9 | // SSSS ttt eeeee llll llll aaaaa |
10 | // |
11 | // Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony |
12 | // and the Stella Team |
13 | // |
14 | // See the file "License.txt" for information on usage and redistribution of |
15 | // this file, and for a DISCLAIMER OF ALL WARRANTIES. |
16 | //============================================================================ |
17 | |
18 | #include <cmath> |
19 | |
20 | #include "PaddleReader.hxx" |
21 | |
22 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
23 | PaddleReader::PaddleReader() |
24 | { |
25 | reset(0); |
26 | } |
27 | |
28 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
29 | void PaddleReader::reset(uInt64 timestamp) |
30 | { |
31 | myU = 0; |
32 | myIsDumped = false; |
33 | |
34 | myValue = 0; |
35 | myTimestamp = timestamp; |
36 | |
37 | setConsoleTiming(ConsoleTiming::ntsc); |
38 | } |
39 | |
40 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
41 | void PaddleReader::vblank(uInt8 value, uInt64 timestamp) |
42 | { |
43 | bool oldIsDumped = myIsDumped; |
44 | |
45 | if (value & 0x80) { |
46 | myIsDumped = true; |
47 | myU = 0; |
48 | myTimestamp = timestamp; |
49 | } else if (oldIsDumped) { |
50 | myIsDumped = false; |
51 | myTimestamp = timestamp; |
52 | } |
53 | } |
54 | |
55 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
56 | uInt8 PaddleReader::inpt(uInt64 timestamp) |
57 | { |
58 | updateCharge(timestamp); |
59 | |
60 | bool state = myIsDumped ? false : myU > myUThresh; |
61 | |
62 | return state ? 0x80 : 0; |
63 | } |
64 | |
65 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
66 | void PaddleReader::update(double value, uInt64 timestamp, ConsoleTiming consoleTiming) |
67 | { |
68 | if (consoleTiming != myConsoleTiming) { |
69 | setConsoleTiming(consoleTiming); |
70 | } |
71 | |
72 | if (value != myValue) { |
73 | myValue = value; |
74 | |
75 | if (myValue < 0) { |
76 | // value < 0 signifies either maximum resistance OR analog input connected to |
77 | // ground (keyboard controllers). As we have no way to tell these apart we just |
78 | // assume ground and discharge. |
79 | myU = 0; |
80 | myTimestamp = timestamp; |
81 | } else { |
82 | updateCharge(timestamp); |
83 | } |
84 | } |
85 | } |
86 | |
87 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
88 | void PaddleReader::setConsoleTiming(ConsoleTiming consoleTiming) |
89 | { |
90 | myConsoleTiming = consoleTiming; |
91 | |
92 | myClockFreq = myConsoleTiming == ConsoleTiming::ntsc ? 60 * 228 * 262 : 50 * 228 * 312; |
93 | myUThresh = USUPP * (1. - exp(-TRIPPOINT_LINES * 228 / myClockFreq / (RPOT + R0) / C)); |
94 | } |
95 | |
96 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
97 | void PaddleReader::updateCharge(uInt64 timestamp) |
98 | { |
99 | if (myIsDumped) return; |
100 | |
101 | if (myValue >= 0) |
102 | myU = USUPP * (1 - (1 - myU / USUPP) * |
103 | exp(-static_cast<double>(timestamp - myTimestamp) / (myValue * RPOT + R0) / C / myClockFreq)); |
104 | |
105 | myTimestamp = timestamp; |
106 | } |
107 | |
108 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
109 | bool PaddleReader::save(Serializer& out) const |
110 | { |
111 | try |
112 | { |
113 | out.putDouble(myUThresh); |
114 | out.putDouble(myU); |
115 | |
116 | out.putDouble(myValue); |
117 | out.putLong(myTimestamp); |
118 | |
119 | out.putInt(int(myConsoleTiming)); |
120 | out.putDouble(myClockFreq); |
121 | |
122 | out.putBool(myIsDumped); |
123 | } |
124 | catch(...) |
125 | { |
126 | cerr << "ERROR: TIA_PaddleReader::save"<< endl; |
127 | return false; |
128 | } |
129 | |
130 | return true; |
131 | } |
132 | |
133 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
134 | bool PaddleReader::load(Serializer& in) |
135 | { |
136 | try |
137 | { |
138 | myUThresh = in.getDouble(); |
139 | myU = in.getDouble(); |
140 | |
141 | myValue = in.getDouble(); |
142 | myTimestamp = in.getLong(); |
143 | |
144 | myConsoleTiming = ConsoleTiming(in.getInt()); |
145 | myClockFreq = in.getDouble(); |
146 | |
147 | myIsDumped = in.getBool(); |
148 | } |
149 | catch(...) |
150 | { |
151 | cerr << "ERROR: TIA_PaddleReader::load"<< endl; |
152 | return false; |
153 | } |
154 | |
155 | return true; |
156 | } |
157 |