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 "System.hxx" |
19 | #include "TIA.hxx" |
20 | #include "M6532.hxx" |
21 | #include "Debugger.hxx" |
22 | #include "Switches.hxx" |
23 | |
24 | #include "RiotDebug.hxx" |
25 | |
26 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
27 | RiotDebug::RiotDebug(Debugger& dbg, Console& console) |
28 | : DebuggerSystem(dbg, console) |
29 | { |
30 | } |
31 | |
32 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
33 | const DebuggerState& RiotDebug::getState() |
34 | { |
35 | // Port A & B registers |
36 | myState.SWCHA_R = swcha(); |
37 | myState.SWCHA_W = mySystem.m6532().myOutA; |
38 | myState.SWACNT = swacnt(); |
39 | myState.SWCHB_R = swchb(); |
40 | myState.SWCHB_W = mySystem.m6532().myOutB; |
41 | myState.SWBCNT = swbcnt(); |
42 | Debugger::set_bits(myState.SWCHA_R, myState.swchaReadBits); |
43 | Debugger::set_bits(myState.SWCHA_W, myState.swchaWriteBits); |
44 | Debugger::set_bits(myState.SWACNT, myState.swacntBits); |
45 | Debugger::set_bits(myState.SWCHB_R, myState.swchbReadBits); |
46 | Debugger::set_bits(myState.SWCHB_W, myState.swchbWriteBits); |
47 | Debugger::set_bits(myState.SWBCNT, myState.swbcntBits); |
48 | |
49 | // TIA INPTx registers |
50 | myState.INPT0 = inpt(0); |
51 | myState.INPT1 = inpt(1); |
52 | myState.INPT2 = inpt(2); |
53 | myState.INPT3 = inpt(3); |
54 | myState.INPT4 = inpt(4); |
55 | myState.INPT5 = inpt(5); |
56 | |
57 | myState.INPTLatch = vblank(6); |
58 | myState.INPTDump = vblank(7); |
59 | |
60 | // Timer registers |
61 | myState.TIM1T = tim1T(); |
62 | myState.TIM8T = tim8T(); |
63 | myState.TIM64T = tim64T(); |
64 | myState.T1024T = tim1024T(); |
65 | myState.INTIM = intim(); |
66 | myState.TIMINT = timint(); |
67 | myState.TIMCLKS = timClocks(); |
68 | myState.INTIMCLKS = intimClocks(); |
69 | myState.TIMDIV = timDivider(); |
70 | |
71 | return myState; |
72 | } |
73 | |
74 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
75 | void RiotDebug::saveOldState() |
76 | { |
77 | // Port A & B registers |
78 | myOldState.SWCHA_R = swcha(); |
79 | myOldState.SWCHA_W = mySystem.m6532().myOutA; |
80 | myOldState.SWACNT = swacnt(); |
81 | myOldState.SWCHB_R = swchb(); |
82 | myOldState.SWCHB_W = mySystem.m6532().myOutB; |
83 | myOldState.SWBCNT = swbcnt(); |
84 | Debugger::set_bits(myOldState.SWCHA_R, myOldState.swchaReadBits); |
85 | Debugger::set_bits(myOldState.SWCHA_W, myOldState.swchaWriteBits); |
86 | Debugger::set_bits(myOldState.SWACNT, myOldState.swacntBits); |
87 | Debugger::set_bits(myOldState.SWCHB_R, myOldState.swchbReadBits); |
88 | Debugger::set_bits(myOldState.SWCHB_W, myOldState.swchbWriteBits); |
89 | Debugger::set_bits(myOldState.SWBCNT, myOldState.swbcntBits); |
90 | |
91 | // TIA INPTx registers |
92 | myOldState.INPT0 = inpt(0); |
93 | myOldState.INPT1 = inpt(1); |
94 | myOldState.INPT2 = inpt(2); |
95 | myOldState.INPT3 = inpt(3); |
96 | myOldState.INPT4 = inpt(4); |
97 | myOldState.INPT5 = inpt(5); |
98 | |
99 | myOldState.INPTLatch = vblank(6); |
100 | myOldState.INPTDump = vblank(7); |
101 | |
102 | // Timer registers |
103 | myOldState.TIM1T = tim1T(); |
104 | myOldState.TIM8T = tim8T(); |
105 | myOldState.TIM64T = tim64T(); |
106 | myOldState.T1024T = tim1024T(); |
107 | myOldState.INTIM = intim(); |
108 | myOldState.TIMINT = timint(); |
109 | myOldState.TIMCLKS = timClocks(); |
110 | myOldState.INTIMCLKS = intimClocks(); |
111 | myOldState.TIMDIV = timDivider(); |
112 | } |
113 | |
114 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
115 | uInt8 RiotDebug::swcha(int newVal) |
116 | { |
117 | if(newVal > -1) |
118 | mySystem.poke(0x280, newVal); |
119 | |
120 | return mySystem.peek(0x280); |
121 | } |
122 | |
123 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
124 | uInt8 RiotDebug::swchb(int newVal) |
125 | { |
126 | if(newVal > -1) |
127 | mySystem.poke(0x282, newVal); |
128 | |
129 | return mySystem.peek(0x282); |
130 | } |
131 | |
132 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
133 | uInt8 RiotDebug::swacnt(int newVal) |
134 | { |
135 | if(newVal > -1) |
136 | mySystem.poke(0x281, newVal); |
137 | |
138 | return mySystem.m6532().myDDRA; |
139 | } |
140 | |
141 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
142 | uInt8 RiotDebug::swbcnt(int newVal) |
143 | { |
144 | if(newVal > -1) |
145 | mySystem.poke(0x283, newVal); |
146 | |
147 | return mySystem.m6532().myDDRB; |
148 | } |
149 | |
150 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
151 | uInt8 RiotDebug::inpt(int x) |
152 | { |
153 | static TIARegister _inpt[6] = { INPT0, INPT1, INPT2, INPT3, INPT4, INPT5 }; |
154 | return mySystem.peek(_inpt[x]); |
155 | } |
156 | |
157 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
158 | bool RiotDebug::vblank(int bit) |
159 | { |
160 | if(bit == 6) // latches |
161 | return myConsole.tia().myInput0.vblankLatched(); |
162 | else if(bit == 7) // dump to ground |
163 | return myConsole.tia().myPaddleReaders[0].vblankDumped(); |
164 | else |
165 | return true; |
166 | } |
167 | |
168 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
169 | uInt8 RiotDebug::tim1T(int newVal) |
170 | { |
171 | if(newVal > -1) |
172 | mySystem.poke(0x294, newVal); |
173 | |
174 | return mySystem.m6532().myOutTimer[0]; |
175 | } |
176 | |
177 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
178 | uInt8 RiotDebug::tim8T(int newVal) |
179 | { |
180 | if(newVal > -1) |
181 | mySystem.poke(0x295, newVal); |
182 | |
183 | return mySystem.m6532().myOutTimer[1]; |
184 | } |
185 | |
186 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
187 | uInt8 RiotDebug::tim64T(int newVal) |
188 | { |
189 | if(newVal > -1) |
190 | mySystem.poke(0x296, newVal); |
191 | |
192 | return mySystem.m6532().myOutTimer[2]; |
193 | } |
194 | |
195 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
196 | uInt8 RiotDebug::tim1024T(int newVal) |
197 | { |
198 | if(newVal > -1) |
199 | mySystem.poke(0x297, newVal); |
200 | |
201 | return mySystem.m6532().myOutTimer[3]; |
202 | } |
203 | |
204 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
205 | uInt8 RiotDebug::intim() const |
206 | { |
207 | return mySystem.m6532().intim(); |
208 | } |
209 | |
210 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
211 | uInt8 RiotDebug::timint() const |
212 | { |
213 | return mySystem.m6532().timint(); |
214 | } |
215 | |
216 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
217 | Int32 RiotDebug::timClocks() const |
218 | { |
219 | return mySystem.m6532().timerClocks(); |
220 | } |
221 | |
222 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
223 | Int32 RiotDebug::intimClocks() const |
224 | { |
225 | return mySystem.m6532().intimClocks(); |
226 | } |
227 | |
228 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
229 | Int32 RiotDebug::timDivider() const |
230 | { |
231 | return mySystem.m6532().myDivider; |
232 | } |
233 | |
234 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
235 | bool RiotDebug::diffP0(int newVal) |
236 | { |
237 | uInt8& switches = myConsole.switches().mySwitches; |
238 | if(newVal > -1) |
239 | switches = Debugger::set_bit(switches, 6, newVal > 0); |
240 | |
241 | return switches & 0x40; |
242 | } |
243 | |
244 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
245 | bool RiotDebug::diffP1(int newVal) |
246 | { |
247 | uInt8& switches = myConsole.switches().mySwitches; |
248 | if(newVal > -1) |
249 | switches = Debugger::set_bit(switches, 7, newVal > 0); |
250 | |
251 | return switches & 0x80; |
252 | } |
253 | |
254 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
255 | bool RiotDebug::tvType(int newVal) |
256 | { |
257 | uInt8& switches = myConsole.switches().mySwitches; |
258 | if(newVal > -1) |
259 | switches = Debugger::set_bit(switches, 3, newVal > 0); |
260 | |
261 | return switches & 0x08; |
262 | } |
263 | |
264 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
265 | bool RiotDebug::select(int newVal) |
266 | { |
267 | uInt8& switches = myConsole.switches().mySwitches; |
268 | if(newVal > -1) |
269 | switches = Debugger::set_bit(switches, 1, newVal > 0); |
270 | |
271 | return switches & 0x02; |
272 | } |
273 | |
274 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
275 | bool RiotDebug::reset(int newVal) |
276 | { |
277 | uInt8& switches = myConsole.switches().mySwitches; |
278 | if(newVal > -1) |
279 | switches = Debugger::set_bit(switches, 0, newVal > 0); |
280 | |
281 | return switches & 0x01; |
282 | } |
283 | |
284 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
285 | string RiotDebug::dirP0String() |
286 | { |
287 | uInt8 reg = swcha(); |
288 | ostringstream buf; |
289 | buf << ((reg & 0x80) ? "" : "right " ) |
290 | << ((reg & 0x40) ? "" : "left " ) |
291 | << ((reg & 0x20) ? "" : "left " ) |
292 | << ((reg & 0x10) ? "" : "left " ) |
293 | << ((reg & 0xf0) == 0xf0 ? "(no directions) " : "" ); |
294 | return buf.str(); |
295 | } |
296 | |
297 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
298 | string RiotDebug::dirP1String() |
299 | { |
300 | uInt8 reg = swcha(); |
301 | ostringstream buf; |
302 | buf << ((reg & 0x08) ? "" : "right " ) |
303 | << ((reg & 0x04) ? "" : "left " ) |
304 | << ((reg & 0x02) ? "" : "left " ) |
305 | << ((reg & 0x01) ? "" : "left " ) |
306 | << ((reg & 0x0f) == 0x0f ? "(no directions) " : "" ); |
307 | return buf.str(); |
308 | } |
309 | |
310 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
311 | string RiotDebug::diffP0String() |
312 | { |
313 | return (swchb() & 0x40) ? "hard/A" : "easy/B" ; |
314 | } |
315 | |
316 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
317 | string RiotDebug::diffP1String() |
318 | { |
319 | return (swchb() & 0x80) ? "hard/A" : "easy/B" ; |
320 | } |
321 | |
322 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
323 | string RiotDebug::tvTypeString() |
324 | { |
325 | return (swchb() & 0x8) ? "Color" : "B&W" ; |
326 | } |
327 | |
328 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
329 | string RiotDebug::switchesString() |
330 | { |
331 | ostringstream buf; |
332 | buf << ((swchb() & 0x2) ? "-" : "+" ) << "select " |
333 | << ((swchb() & 0x1) ? "-" : "+" ) << "reset" ; |
334 | return buf.str(); |
335 | } |
336 | |
337 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
338 | string RiotDebug::toString() |
339 | { |
340 | const RiotState& state = static_cast<const RiotState&>(getState()); |
341 | const RiotState& oldstate = static_cast<const RiotState&>(getOldState()); |
342 | |
343 | ostringstream buf; |
344 | buf << "280/SWCHA(R)=" << myDebugger.invIfChanged(state.SWCHA_R, oldstate.SWCHA_R) |
345 | << " 280/SWCHA(W)=" << myDebugger.invIfChanged(state.SWCHA_W, oldstate.SWCHA_W) |
346 | << " 281/SWACNT=" << myDebugger.invIfChanged(state.SWACNT, oldstate.SWACNT) |
347 | << endl |
348 | << "282/SWCHB(R)=" << myDebugger.invIfChanged(state.SWCHB_R, oldstate.SWCHB_R) |
349 | << " 282/SWCHB(W)=" << myDebugger.invIfChanged(state.SWCHB_W, oldstate.SWCHB_W) |
350 | << " 283/SWBCNT=" << myDebugger.invIfChanged(state.SWBCNT, oldstate.SWBCNT) |
351 | << endl |
352 | |
353 | // These are squirrely: some symbol files will define these as |
354 | // 0x284-0x287. Doesn't actually matter, these registers repeat |
355 | // every 16 bytes. |
356 | << "294/TIM1T=" << myDebugger.invIfChanged(state.TIM1T, oldstate.TIM1T) |
357 | << " 295/TIM8T=" << myDebugger.invIfChanged(state.TIM8T, oldstate.TIM8T) |
358 | << " 296/TIM64T=" << myDebugger.invIfChanged(state.TIM64T, oldstate.TIM64T) |
359 | << " 297/T1024T=" << myDebugger.invIfChanged(state.T1024T, oldstate.T1024T) |
360 | << endl |
361 | |
362 | << "0x284/INTIM=" << myDebugger.invIfChanged(state.INTIM, oldstate.INTIM) |
363 | << " 285/TIMINT=" << myDebugger.invIfChanged(state.TIMINT, oldstate.TIMINT) |
364 | << " Timer_Clocks=" << myDebugger.invIfChanged(state.TIMCLKS, oldstate.TIMCLKS) |
365 | << " INTIM_Clocks=" << myDebugger.invIfChanged(state.INTIMCLKS, oldstate.INTIMCLKS) |
366 | << " Divider=" << myDebugger.invIfChanged(state.TIMDIV, oldstate.TIMDIV) |
367 | << endl |
368 | |
369 | << "Left/P0diff: " << diffP0String() << " Right/P1diff: " << diffP0String() |
370 | << endl |
371 | << "TVType: " << tvTypeString() << " Switches: " << switchesString() |
372 | << endl |
373 | |
374 | // Yes, the fire buttons are in the TIA, but we might as well |
375 | // show them here for convenience. |
376 | << "Left/P0 stick: " << dirP0String() |
377 | << ((mySystem.peek(0x03c) & 0x80) ? "" : "(button) " ) |
378 | << endl |
379 | << "Right/P1 stick: " << dirP1String() |
380 | << ((mySystem.peek(0x03d) & 0x80) ? "" : "(button) " ); |
381 | |
382 | return buf.str(); |
383 | } |
384 | |