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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
27RiotDebug::RiotDebug(Debugger& dbg, Console& console)
28 : DebuggerSystem(dbg, console)
29{
30}
31
32// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
33const 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
75void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
115uInt8 RiotDebug::swcha(int newVal)
116{
117 if(newVal > -1)
118 mySystem.poke(0x280, newVal);
119
120 return mySystem.peek(0x280);
121}
122
123// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
124uInt8 RiotDebug::swchb(int newVal)
125{
126 if(newVal > -1)
127 mySystem.poke(0x282, newVal);
128
129 return mySystem.peek(0x282);
130}
131
132// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
133uInt8 RiotDebug::swacnt(int newVal)
134{
135 if(newVal > -1)
136 mySystem.poke(0x281, newVal);
137
138 return mySystem.m6532().myDDRA;
139}
140
141// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
142uInt8 RiotDebug::swbcnt(int newVal)
143{
144 if(newVal > -1)
145 mySystem.poke(0x283, newVal);
146
147 return mySystem.m6532().myDDRB;
148}
149
150// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
151uInt8 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
158bool 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
169uInt8 RiotDebug::tim1T(int newVal)
170{
171 if(newVal > -1)
172 mySystem.poke(0x294, newVal);
173
174 return mySystem.m6532().myOutTimer[0];
175}
176
177// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
178uInt8 RiotDebug::tim8T(int newVal)
179{
180 if(newVal > -1)
181 mySystem.poke(0x295, newVal);
182
183 return mySystem.m6532().myOutTimer[1];
184}
185
186// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
187uInt8 RiotDebug::tim64T(int newVal)
188{
189 if(newVal > -1)
190 mySystem.poke(0x296, newVal);
191
192 return mySystem.m6532().myOutTimer[2];
193}
194
195// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
196uInt8 RiotDebug::tim1024T(int newVal)
197{
198 if(newVal > -1)
199 mySystem.poke(0x297, newVal);
200
201 return mySystem.m6532().myOutTimer[3];
202}
203
204// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
205uInt8 RiotDebug::intim() const
206{
207 return mySystem.m6532().intim();
208}
209
210// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
211uInt8 RiotDebug::timint() const
212{
213 return mySystem.m6532().timint();
214}
215
216// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
217Int32 RiotDebug::timClocks() const
218{
219 return mySystem.m6532().timerClocks();
220}
221
222// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
223Int32 RiotDebug::intimClocks() const
224{
225 return mySystem.m6532().intimClocks();
226}
227
228// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
229Int32 RiotDebug::timDivider() const
230{
231 return mySystem.m6532().myDivider;
232}
233
234// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
235bool 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
245bool 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
255bool 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
265bool 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
275bool 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
285string 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
298string 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
311string RiotDebug::diffP0String()
312{
313 return (swchb() & 0x40) ? "hard/A" : "easy/B";
314}
315
316// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
317string RiotDebug::diffP1String()
318{
319 return (swchb() & 0x80) ? "hard/A" : "easy/B";
320}
321
322// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
323string RiotDebug::tvTypeString()
324{
325 return (swchb() & 0x8) ? "Color" : "B&W";
326}
327
328// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
329string RiotDebug::switchesString()
330{
331 ostringstream buf;
332 buf << ((swchb() & 0x2) ? "-" : "+") << "select "
333 << ((swchb() & 0x1) ? "-" : "+") << "reset";
334 return buf.str();
335}
336
337// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
338string 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