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 "Base.hxx"
19#include "System.hxx"
20#include "Debugger.hxx"
21#include "TIA.hxx"
22#include "DelayQueueIterator.hxx"
23
24#include "TIADebug.hxx"
25
26// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
27TIADebug::TIADebug(Debugger& dbg, Console& console)
28 : DebuggerSystem(dbg, console),
29 myTIA(console.tia())
30{
31}
32
33// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
34const DebuggerState& TIADebug::getState()
35{
36 // Color registers
37 myState.coluRegs.clear();
38 myState.coluRegs.push_back(coluP0());
39 myState.coluRegs.push_back(coluP1());
40 myState.coluRegs.push_back(coluPF());
41 myState.coluRegs.push_back(coluBK());
42
43 // Debug Colors
44 int timing = myConsole.timing() == ConsoleTiming::ntsc ? 0
45 : myConsole.timing() == ConsoleTiming::pal ? 1 : 2;
46
47 myState.fixedCols.clear();
48 myState.fixedCols.push_back(myTIA.myFixedColorPalette[timing][TIA::P0]);
49 myState.fixedCols.push_back(myTIA.myFixedColorPalette[timing][TIA::P1]);
50 myState.fixedCols.push_back(myTIA.myFixedColorPalette[timing][TIA::PF]);
51 myState.fixedCols.push_back(myTIA.myFixedColorPalette[timing][TIA::BK]);
52 myState.fixedCols.push_back(myTIA.myFixedColorPalette[timing][TIA::M0]);
53 myState.fixedCols.push_back(myTIA.myFixedColorPalette[timing][TIA::M1]);
54 myState.fixedCols.push_back(myTIA.myFixedColorPalette[timing][TIA::BL]);
55 myState.fixedCols.push_back(TIA::FixedColor::HBLANK_WHITE);
56
57 // Collisions
58 myState.cx.clear();
59 myState.cx.push_back(collP0_PF());
60 myState.cx.push_back(collP0_BL());
61 myState.cx.push_back(collM1_P0());
62 myState.cx.push_back(collM0_P0());
63 myState.cx.push_back(collP0_P1());
64 myState.cx.push_back(collP1_PF());
65 myState.cx.push_back(collP1_BL());
66 myState.cx.push_back(collM1_P1());
67 myState.cx.push_back(collM0_P1());
68 myState.cx.push_back(collM0_PF());
69 myState.cx.push_back(collM0_BL());
70 myState.cx.push_back(collM0_M1());
71 myState.cx.push_back(collM1_PF());
72 myState.cx.push_back(collM1_BL());
73 myState.cx.push_back(collBL_PF());
74
75 // Player 0 & 1 and Ball graphics registers
76 myState.gr.clear();
77 myState.gr.push_back(myTIA.myPlayer0.getGRPNew());
78 myState.gr.push_back(myTIA.myPlayer1.getGRPNew());
79 myState.gr.push_back(myTIA.myPlayer0.getGRPOld());
80 myState.gr.push_back(myTIA.myPlayer1.getGRPOld());
81 myState.gr.push_back(myTIA.myBall.getENABLNew());
82 myState.gr.push_back(myTIA.myBall.getENABLOld());
83
84 // Player 0 & 1, Missile 0 & 1 and Ball graphics status registers
85 myState.ref.clear();
86 myState.ref.push_back(refP0());
87 myState.ref.push_back(refP1());
88 myState.vdel.clear();
89 myState.vdel.push_back(vdelP0());
90 myState.vdel.push_back(vdelP1());
91 myState.vdel.push_back(vdelBL());
92 myState.res.clear();
93 myState.res.push_back(resMP0());
94 myState.res.push_back(resMP1());
95
96 // Position registers
97 myState.pos.clear();
98 myState.pos.push_back(posP0());
99 myState.pos.push_back(posP1());
100 myState.pos.push_back(posM0());
101 myState.pos.push_back(posM1());
102 myState.pos.push_back(posBL());
103
104 // Horizontal move registers
105 myState.hm.clear();
106 myState.hm.push_back(hmP0());
107 myState.hm.push_back(hmP1());
108 myState.hm.push_back(hmM0());
109 myState.hm.push_back(hmM1());
110 myState.hm.push_back(hmBL());
111
112 // Playfield registers
113 myState.pf.clear();
114 myState.pf.push_back(pf0());
115 myState.pf.push_back(pf1());
116 myState.pf.push_back(pf2());
117 myState.pf.push_back(refPF());
118 myState.pf.push_back(scorePF());
119 myState.pf.push_back(priorityPF());
120
121 // Size registers
122 myState.size.clear();
123 myState.size.push_back(nusizP0());
124 myState.size.push_back(nusizP1());
125 myState.size.push_back(nusizM0());
126 myState.size.push_back(nusizM1());
127 myState.size.push_back(sizeBL());
128
129 // Audio registers
130 myState.aud.clear();
131 myState.aud.push_back(audF0());
132 myState.aud.push_back(audF1());
133 myState.aud.push_back(audC0());
134 myState.aud.push_back(audC1());
135 myState.aud.push_back(audV0());
136 myState.aud.push_back(audV1());
137
138 // internal TIA state
139 myState.info.clear();
140 myState.info.push_back(frameCount());
141 myState.info.push_back(frameCycles());
142 myState.info.push_back(vsyncAsInt());
143 myState.info.push_back(vblankAsInt());
144 myState.info.push_back(scanlines());
145 myState.info.push_back(scanlinesLastFrame());
146 myState.info.push_back(clocksThisLine());
147
148 return myState;
149}
150
151// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
152void TIADebug::saveOldState()
153{
154 // Color registers
155 myOldState.coluRegs.clear();
156 myOldState.coluRegs.push_back(coluP0());
157 myOldState.coluRegs.push_back(coluP1());
158 myOldState.coluRegs.push_back(coluPF());
159 myOldState.coluRegs.push_back(coluBK());
160
161 // Collisions
162 myOldState.cx.clear();
163 myOldState.cx.push_back(collP0_PF());
164 myOldState.cx.push_back(collP0_BL());
165 myOldState.cx.push_back(collM1_P0());
166 myOldState.cx.push_back(collM0_P0());
167 myOldState.cx.push_back(collP0_P1());
168 myOldState.cx.push_back(collP1_PF());
169 myOldState.cx.push_back(collP1_BL());
170 myOldState.cx.push_back(collM1_P1());
171 myOldState.cx.push_back(collM0_P1());
172 myOldState.cx.push_back(collM0_PF());
173 myOldState.cx.push_back(collM0_BL());
174 myOldState.cx.push_back(collM0_M1());
175 myOldState.cx.push_back(collM1_PF());
176 myOldState.cx.push_back(collM1_BL());
177 myOldState.cx.push_back(collBL_PF());
178
179 // Player 0 & 1 graphics registers
180 myOldState.gr.clear();
181 myOldState.gr.push_back(myTIA.myPlayer0.getGRPNew());
182 myOldState.gr.push_back(myTIA.myPlayer1.getGRPNew());
183 myOldState.gr.push_back(myTIA.myPlayer0.getGRPOld());
184 myOldState.gr.push_back(myTIA.myPlayer1.getGRPOld());
185 myOldState.gr.push_back(myTIA.myBall.getENABLNew());
186 myOldState.gr.push_back(myTIA.myBall.getENABLOld());
187
188 // Player 0 & 1, Missile 0 & 1 and Ball graphics status registers
189 myOldState.ref.clear();
190 myOldState.ref.push_back(refP0());
191 myOldState.ref.push_back(refP1());
192 myOldState.vdel.clear();
193 myOldState.vdel.push_back(vdelP0());
194 myOldState.vdel.push_back(vdelP1());
195 myOldState.vdel.push_back(vdelBL());
196 myOldState.res.clear();
197 myOldState.res.push_back(resMP0());
198 myOldState.res.push_back(resMP1());
199
200 // Position registers
201 myOldState.pos.clear();
202 myOldState.pos.push_back(posP0());
203 myOldState.pos.push_back(posP1());
204 myOldState.pos.push_back(posM0());
205 myOldState.pos.push_back(posM1());
206 myOldState.pos.push_back(posBL());
207
208 // Horizontal move registers
209 myOldState.hm.clear();
210 myOldState.hm.push_back(hmP0());
211 myOldState.hm.push_back(hmP1());
212 myOldState.hm.push_back(hmM0());
213 myOldState.hm.push_back(hmM1());
214 myOldState.hm.push_back(hmBL());
215
216 // Playfield registers
217 myOldState.pf.clear();
218 myOldState.pf.push_back(pf0());
219 myOldState.pf.push_back(pf1());
220 myOldState.pf.push_back(pf2());
221 myOldState.pf.push_back(refPF());
222 myOldState.pf.push_back(scorePF());
223 myOldState.pf.push_back(priorityPF());
224
225 // Size registers
226 myOldState.size.clear();
227 myOldState.size.push_back(nusizP0());
228 myOldState.size.push_back(nusizP1());
229 myOldState.size.push_back(nusizM0());
230 myOldState.size.push_back(nusizM1());
231 myOldState.size.push_back(sizeBL());
232
233 // Audio registers
234 myOldState.aud.clear();
235 myOldState.aud.push_back(audF0());
236 myOldState.aud.push_back(audF1());
237 myOldState.aud.push_back(audC0());
238 myOldState.aud.push_back(audC1());
239 myOldState.aud.push_back(audV0());
240 myOldState.aud.push_back(audV1());
241
242 // internal TIA state
243 myOldState.info.clear();
244 myOldState.info.push_back(frameCount());
245 myOldState.info.push_back(frameCycles());
246 myOldState.info.push_back(vsyncAsInt());
247 myOldState.info.push_back(vblankAsInt());
248 myOldState.info.push_back(scanlines());
249 myOldState.info.push_back(scanlinesLastFrame());
250 myOldState.info.push_back(clocksThisLine());
251}
252
253/* the set methods now use mySystem.poke(). This will save us the
254 trouble of masking the values here, since TIA::poke() will do it
255 for us.
256
257 This means that the GUI should *never* just display the value the
258 user entered: it should always read the return value of the set
259 method and display that.
260
261 An Example:
262
263 User enters "ff" in the AUDV0 field. GUI calls value = tiaDebug->audV0(0xff).
264 The AUDV0 register is only 4 bits wide, so "value" is 0x0f. That's what
265 should be displayed.
266
267 In a perfect world, the GUI would only allow one hex digit to be entered...
268 but we allow decimal or binary input in the GUI (with # or \ prefix). The
269 only way to make that work would be to validate the data entry after every
270 keystroke... which would be a pain for both us and the user. Using poke()
271 here is a compromise that allows the TIA to do the range-checking for us,
272 so the GUI and/or TIADebug don't have to duplicate logic from TIA::poke().
273*/
274
275// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
276bool TIADebug::vdelP0(int newVal)
277{
278 if(newVal > -1)
279 mySystem.poke(VDELP0, bool(newVal));
280
281 return myTIA.registerValue(VDELP0) & 0x01;
282}
283
284// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
285bool TIADebug::vdelP1(int newVal)
286{
287 if(newVal > -1)
288 mySystem.poke(VDELP1, bool(newVal));
289
290 return myTIA.registerValue(VDELP1) & 0x01;
291}
292
293// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
294bool TIADebug::vdelBL(int newVal)
295{
296 if(newVal > -1)
297 mySystem.poke(VDELBL, bool(newVal));
298
299 return myTIA.registerValue(VDELBL) & 0x01;
300}
301
302// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
303bool TIADebug::enaM0(int newVal)
304{
305 if(newVal > -1)
306 mySystem.poke(ENAM0, bool(newVal) << 1);
307
308 return myTIA.registerValue(ENAM0) & 0x02;
309}
310
311// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
312bool TIADebug::enaM1(int newVal)
313{
314 if(newVal > -1)
315 mySystem.poke(ENAM1, bool(newVal) << 1);
316
317 return myTIA.registerValue(ENAM1) & 0x02;
318}
319
320// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
321bool TIADebug::enaBL(int newVal)
322{
323 if(newVal > -1)
324 mySystem.poke(ENABL, bool(newVal) << 1);
325
326 return myTIA.registerValue(ENABL) & 0x02;
327}
328
329// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
330bool TIADebug::resMP0(int newVal)
331{
332 if(newVal > -1)
333 mySystem.poke(RESMP0, bool(newVal) << 1);
334
335 return myTIA.registerValue(RESMP0) & 0x02;
336}
337
338// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
339bool TIADebug::resMP1(int newVal)
340{
341 if(newVal > -1)
342 mySystem.poke(RESMP1, bool(newVal) << 1);
343
344 return myTIA.registerValue(RESMP1) & 0x02;
345}
346
347// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
348bool TIADebug::refP0(int newVal)
349{
350 if(newVal > -1)
351 mySystem.poke(REFP0, bool(newVal) << 3);
352
353 return myTIA.registerValue(REFP0) & 0x08;
354}
355
356// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
357bool TIADebug::refP1(int newVal)
358{
359 if(newVal > -1)
360 mySystem.poke(REFP1, bool(newVal) << 3);
361
362 return myTIA.registerValue(REFP1) & 0x08;
363}
364
365// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
366bool TIADebug::refPF(int newVal)
367{
368 if(newVal > -1)
369 {
370 int tmp = myTIA.registerValue(CTRLPF);
371 if(newVal)
372 tmp |= 0x01;
373 else
374 tmp &= ~0x01;
375 mySystem.poke(CTRLPF, tmp);
376 }
377
378 return myTIA.registerValue(CTRLPF) & 0x01;
379}
380
381// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
382bool TIADebug::scorePF(int newVal)
383{
384 if(newVal > -1)
385 {
386 int tmp = myTIA.registerValue(CTRLPF);
387 if(newVal)
388 tmp |= 0x02;
389 else
390 tmp &= ~0x02;
391 mySystem.poke(CTRLPF, tmp);
392 }
393
394 return myTIA.registerValue(CTRLPF) & 0x02;
395}
396
397// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
398bool TIADebug::priorityPF(int newVal)
399{
400 if(newVal > -1)
401 {
402 int tmp = myTIA.registerValue(CTRLPF);
403 if(newVal)
404 tmp |= 0x04;
405 else
406 tmp &= ~0x04;
407 mySystem.poke(CTRLPF, tmp);
408 }
409
410 return myTIA.registerValue(CTRLPF) & 0x04;
411}
412
413// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
414bool TIADebug::collision(CollisionBit id, bool toggle) const
415{
416 switch(id)
417 {
418 case CollisionBit::M0P1:
419 if(toggle)
420 myTIA.toggleCollP1M0();
421 return myTIA.collCXM0P() & 0x80;
422
423 case CollisionBit::M0P0:
424 if(toggle)
425 myTIA.toggleCollP0M0();
426 return myTIA.collCXM0P() & 0x40;
427
428 case CollisionBit::M1P0:
429 if(toggle)
430 myTIA.toggleCollP0M1();
431 return myTIA.collCXM1P() & 0x80;
432
433 case CollisionBit::M1P1:
434 if(toggle)
435 myTIA.toggleCollP1M1();
436 return myTIA.collCXM1P() & 0x40;
437
438 case CollisionBit::P0PF:
439 if(toggle)
440 myTIA.toggleCollP0PF();
441 return myTIA.collCXP0FB() & 0x80;
442 case CollisionBit::P0BL:
443 if(toggle)
444 myTIA.toggleCollP0BL();
445 return myTIA.collCXP0FB() & 0x40;
446
447 case CollisionBit::P1PF:
448 if(toggle)
449 myTIA.toggleCollP1PF();
450 return myTIA.collCXP1FB() & 0x80;
451
452 case CollisionBit::P1BL:
453 if(toggle)
454 myTIA.toggleCollP1BL();
455 return myTIA.collCXP1FB() & 0x40;
456
457 case CollisionBit::M0PF:
458 if(toggle)
459 myTIA.toggleCollM0PF();
460 return myTIA.collCXM0FB() & 0x80;
461
462 case CollisionBit::M0BL:
463 if(toggle)
464 myTIA.toggleCollM0BL();
465 return myTIA.collCXM0FB() & 0x40;
466
467 case CollisionBit::M1PF:
468 if(toggle)
469 myTIA.toggleCollM1PF();
470 return myTIA.collCXM1FB() & 0x80;
471
472 case CollisionBit::M1BL:
473 if(toggle)
474 myTIA.toggleCollM1BL();
475 return myTIA.collCXM1FB() & 0x40;
476
477 case CollisionBit::BLPF:
478 if(toggle)
479 myTIA.toggleCollBLPF();
480 return myTIA.collCXBLPF() & 0x80;
481
482 case CollisionBit::P0P1:
483 if(toggle)
484 myTIA.toggleCollP0P1();
485 return myTIA.collCXPPMM() & 0x80;
486
487 case CollisionBit::M0M1:
488 if(toggle)
489 myTIA.toggleCollM0M1();
490 return myTIA.collCXPPMM() & 0x40;
491 }
492 return false; // make compiler happy
493}
494
495// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
496uInt8 TIADebug::audC0(int newVal)
497{
498 if(newVal > -1)
499 mySystem.poke(AUDC0, newVal);
500
501 return myTIA.registerValue(AUDC0) & 0x0f;
502}
503
504// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
505uInt8 TIADebug::audC1(int newVal)
506{
507 if(newVal > -1)
508 mySystem.poke(AUDC1, newVal);
509
510 return myTIA.registerValue(AUDC1) & 0x0f;
511}
512
513// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
514uInt8 TIADebug::audV0(int newVal)
515{
516 if(newVal > -1)
517 mySystem.poke(AUDV0, newVal);
518
519 return myTIA.registerValue(AUDV0) & 0x0f;
520}
521
522// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
523uInt8 TIADebug::audV1(int newVal)
524{
525 if(newVal > -1)
526 mySystem.poke(AUDV1, newVal);
527
528 return myTIA.registerValue(AUDV1) & 0x0f;
529}
530
531// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
532uInt8 TIADebug::audF0(int newVal)
533{
534 if(newVal > -1)
535 mySystem.poke(AUDF0, newVal);
536
537 return myTIA.registerValue(AUDF0) & 0x1f;
538}
539
540// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
541uInt8 TIADebug::audF1(int newVal)
542{
543 if(newVal > -1)
544 mySystem.poke(AUDF1, newVal);
545
546 return myTIA.registerValue(AUDF1) & 0x1f;
547}
548
549// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
550uInt8 TIADebug::pf0(int newVal)
551{
552 if(newVal > -1)
553 mySystem.poke(PF0, newVal << 4);
554
555 return myTIA.registerValue(PF0) >> 4;
556}
557
558// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
559uInt8 TIADebug::pf1(int newVal)
560{
561 if(newVal > -1)
562 mySystem.poke(PF1, newVal);
563
564 return myTIA.registerValue(PF1);
565}
566
567// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
568uInt8 TIADebug::pf2(int newVal)
569{
570 if(newVal > -1)
571 mySystem.poke(PF2, newVal);
572
573 return myTIA.registerValue(PF2);
574}
575
576// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
577uInt8 TIADebug::coluP0(int newVal)
578{
579 if(newVal > -1)
580 mySystem.poke(COLUP0, newVal);
581
582 return myTIA.registerValue(COLUP0);
583}
584
585// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
586uInt8 TIADebug::coluP1(int newVal)
587{
588 if(newVal > -1)
589 mySystem.poke(COLUP1, newVal);
590
591 return myTIA.registerValue(COLUP1);
592}
593
594// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
595uInt8 TIADebug::coluPF(int newVal)
596{
597 if(newVal > -1)
598 mySystem.poke(COLUPF, newVal);
599
600 return myTIA.registerValue(COLUPF);
601}
602
603// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
604uInt8 TIADebug::coluBK(int newVal)
605{
606 if(newVal > -1)
607 mySystem.poke(COLUBK, newVal);
608
609 return myTIA.registerValue(COLUBK);
610}
611
612// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
613uInt8 TIADebug::nusiz0(int newVal)
614{
615 if(newVal > -1)
616 mySystem.poke(NUSIZ0, newVal);
617
618 return myTIA.registerValue(NUSIZ0);
619}
620
621// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
622uInt8 TIADebug::nusiz1(int newVal)
623{
624 if(newVal > -1)
625 mySystem.poke(NUSIZ1, newVal);
626
627 return myTIA.registerValue(NUSIZ1);
628}
629
630// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
631uInt8 TIADebug::nusizP0(int newVal)
632{
633 if(newVal > -1)
634 {
635 uInt8 tmp = myTIA.registerValue(NUSIZ0) & ~0x07;
636 tmp |= (newVal & 0x07);
637 mySystem.poke(NUSIZ0, tmp);
638 }
639
640 return myTIA.registerValue(NUSIZ0) & 0x07;
641}
642
643// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
644uInt8 TIADebug::nusizP1(int newVal)
645{
646 if(newVal > -1)
647 {
648 uInt8 tmp = myTIA.registerValue(NUSIZ1) & ~0x07;
649 tmp |= newVal & 0x07;
650 mySystem.poke(NUSIZ1, tmp);
651 }
652
653 return myTIA.registerValue(NUSIZ1) & 0x07;
654}
655
656// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
657uInt8 TIADebug::nusizM0(int newVal)
658{
659 if(newVal > -1)
660 {
661 uInt8 tmp = myTIA.registerValue(NUSIZ0) & ~0x30;
662 tmp |= (newVal & 0x04) << 4;
663 mySystem.poke(NUSIZ0, tmp);
664 }
665
666 return (myTIA.registerValue(NUSIZ0) & 0x30) >> 4;
667}
668
669// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
670uInt8 TIADebug::nusizM1(int newVal)
671{
672 if(newVal > -1)
673 {
674 uInt8 tmp = myTIA.registerValue(NUSIZ1) & ~0x30;
675 tmp |= (newVal & 0x04) << 4;
676 mySystem.poke(NUSIZ1, tmp);
677 }
678
679 return (myTIA.registerValue(NUSIZ1) & 0x30) >> 4;
680}
681
682// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
683uInt8 TIADebug::grP0(int newVal)
684{
685 if(newVal > -1)
686 mySystem.poke(GRP0, newVal);
687
688 return myTIA.registerValue(GRP0);
689}
690
691// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
692uInt8 TIADebug::grP1(int newVal)
693{
694 if(newVal > -1)
695 mySystem.poke(GRP1, newVal);
696
697 return myTIA.registerValue(GRP1);
698}
699
700// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
701uInt8 TIADebug::posP0(int newVal)
702{
703 if(newVal > -1)
704 myTIA.myPlayer0.setPosition(newVal);
705
706 return myTIA.myPlayer0.getPosition();
707}
708
709// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
710uInt8 TIADebug::posP1(int newVal)
711{
712 if(newVal > -1)
713 myTIA.myPlayer1.setPosition(newVal);
714
715 return myTIA.myPlayer1.getPosition();
716}
717
718// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
719uInt8 TIADebug::posM0(int newVal)
720{
721 if(newVal > -1)
722 myTIA.myMissile0.setPosition(newVal);
723
724 return myTIA.myMissile0.getPosition();
725}
726
727// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
728uInt8 TIADebug::posM1(int newVal)
729{
730 if(newVal > -1)
731 myTIA.myMissile1.setPosition(newVal);
732
733 return myTIA.myMissile1.getPosition();
734}
735
736// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
737uInt8 TIADebug::posBL(int newVal)
738{
739 if(newVal > -1)
740 myTIA.myBall.setPosition(newVal);
741
742 return myTIA.myBall.getPosition();
743}
744
745// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
746uInt8 TIADebug::ctrlPF(int newVal)
747{
748 if(newVal > -1)
749 mySystem.poke(CTRLPF, newVal);
750
751 return myTIA.registerValue(CTRLPF);
752}
753
754// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
755uInt8 TIADebug::sizeBL(int newVal)
756{
757 if(newVal > -1)
758 {
759 uInt8 tmp = myTIA.registerValue(CTRLPF) & ~0x30;
760 tmp |= (newVal & 0x04) << 4;
761 mySystem.poke(CTRLPF, tmp);
762 }
763
764 return (myTIA.registerValue(CTRLPF) & 0x30) >> 4;
765}
766
767// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
768uInt8 TIADebug::hmP0(int newVal)
769{
770 if(newVal > -1)
771 mySystem.poke(HMP0, newVal << 4);
772
773 return myTIA.registerValue(HMP0) >> 4;
774}
775
776// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
777uInt8 TIADebug::hmP1(int newVal)
778{
779 if(newVal > -1)
780 mySystem.poke(HMP1, newVal << 4);
781
782 return myTIA.registerValue(HMP1) >> 4;
783}
784
785// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
786uInt8 TIADebug::hmM0(int newVal)
787{
788 if(newVal > -1)
789 mySystem.poke(HMM0, newVal << 4);
790
791 return myTIA.registerValue(HMM0) >> 4;
792}
793
794// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
795uInt8 TIADebug::hmM1(int newVal)
796{
797 if(newVal > -1)
798 mySystem.poke(HMM1, newVal << 4);
799
800 return myTIA.registerValue(HMM1) >> 4;
801}
802
803// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
804uInt8 TIADebug::hmBL(int newVal)
805{
806 if(newVal > -1)
807 mySystem.poke(HMBL, newVal << 4);
808
809 return myTIA.registerValue(HMBL) >> 4;
810}
811
812// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
813void TIADebug::setGRP0Old(uInt8 b)
814{
815 myTIA.myPlayer0.setGRPOld(b);
816}
817
818// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
819void TIADebug::setGRP1Old(uInt8 b)
820{
821 myTIA.myPlayer1.setGRPOld(b);
822}
823
824// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
825void TIADebug::setENABLOld(bool b)
826{
827 myTIA.myBall.setENABLOld(b);
828}
829
830// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
831void TIADebug::strobeWsync()
832{
833 mySystem.poke(WSYNC, 0);
834}
835
836// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
837void TIADebug::strobeRsync()
838{
839 mySystem.poke(RSYNC, 0);
840}
841
842// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
843void TIADebug::strobeResP0()
844{
845 mySystem.poke(RESP0, 0);
846}
847
848// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
849void TIADebug::strobeResP1()
850{
851 mySystem.poke(RESP1, 0);
852}
853
854// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
855void TIADebug::strobeResM0()
856{
857 mySystem.poke(RESM0, 0);
858}
859
860// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
861void TIADebug::strobeResM1()
862{
863 mySystem.poke(RESM1, 0);
864}
865
866// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
867void TIADebug::strobeResBL()
868{
869 mySystem.poke(RESBL, 0);
870}
871
872// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
873void TIADebug::strobeHmove()
874{
875 mySystem.poke(HMOVE, 0);
876}
877
878// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
879void TIADebug::strobeHmclr()
880{
881 mySystem.poke(HMCLR, 0);
882}
883
884// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
885void TIADebug::strobeCxclr()
886{
887 mySystem.poke(CXCLR, 0);
888}
889
890// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
891int TIADebug::frameCount() const
892{
893 return myTIA.frameCount();
894}
895
896// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
897int TIADebug::frameCycles() const
898{
899 return myTIA.frameCycles();
900}
901
902// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
903int TIADebug::cyclesLo() const
904{
905 return int(myTIA.cycles());
906}
907
908// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
909int TIADebug::cyclesHi() const
910{
911 return int(myTIA.cycles() >> 32);
912}
913
914// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
915int TIADebug::scanlines() const
916{
917 return myTIA.scanlines();
918}
919
920// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
921int TIADebug::scanlinesLastFrame() const
922{
923 return myTIA.scanlinesLastFrame();
924}
925
926// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
927int TIADebug::clocksThisLine() const
928{
929 return myTIA.clocksThisLine();
930}
931
932// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
933int TIADebug::cyclesThisLine() const
934{
935 return myTIA.clocksThisLine()/3;
936}
937
938// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
939bool TIADebug::vsync() const
940{
941 return myTIA.registerValue(VSYNC) & 0x02;
942}
943
944// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
945bool TIADebug::vblank() const
946{
947 return myTIA.registerValue(VBLANK) & 0x02;
948}
949
950// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
951shared_ptr<DelayQueueIterator> TIADebug::delayQueueIterator() const
952{
953 return myTIA.delayQueueIterator();
954}
955
956// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
957string TIADebug::colorSwatch(uInt8 c) const
958{
959 string ret;
960
961 ret += char((c >> 1) | 0x80);
962 ret += "\177 ";
963 ret += "\177\001 ";
964
965 return ret;
966}
967
968// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
969// FIXME - how does this work; is this even needed ??
970string TIADebug::audFreq(uInt8 div)
971{
972 string ret;
973 char buf[10];
974
975 double hz = 31400.0;
976 if(div) hz /= div;
977 std::snprintf(buf, 9, "%5.1f", hz);
978 ret += buf;
979 ret += "Hz";
980
981 return ret;
982}
983
984// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
985string TIADebug::booleanWithLabel(string label, bool value)
986{
987 if(value)
988 return "+" + BSPF::toUpperCase(label);
989 else
990 return "-" + BSPF::toLowerCase(label);
991}
992
993// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
994string TIADebug::debugColors() const
995{
996 ostringstream buf;
997
998 int timing = myConsole.timing() == ConsoleTiming::ntsc ? 0
999 : myConsole.timing() == ConsoleTiming::pal ? 1 : 2;
1000
1001 buf << " " << myTIA.myFixedColorNames[TIA::P0] << " " << colorSwatch(myTIA.myFixedColorPalette[timing][TIA::P0])
1002 << " Player 0\n"
1003 << " " << myTIA.myFixedColorNames[TIA::M0] << " " << colorSwatch(myTIA.myFixedColorPalette[timing][TIA::M0])
1004 << " Missile 0\n"
1005 << " " << myTIA.myFixedColorNames[TIA::P1] << " " << colorSwatch(myTIA.myFixedColorPalette[timing][TIA::P1])
1006 << " Player 1\n"
1007 << " " << myTIA.myFixedColorNames[TIA::M1] << " " << colorSwatch(myTIA.myFixedColorPalette[timing][TIA::M1])
1008 << " Missile 1\n"
1009 << " " << myTIA.myFixedColorNames[TIA::PF] << " " << colorSwatch(myTIA.myFixedColorPalette[timing][TIA::PF])
1010 << " Playfield\n"
1011 << " " << myTIA.myFixedColorNames[TIA::BL] << " " << colorSwatch(myTIA.myFixedColorPalette[timing][TIA::BL])
1012 << " Ball\n"
1013 << " Grey " << colorSwatch(myTIA.myFixedColorPalette[timing][TIA::BK])
1014 << " Background\n"
1015 << " White " << colorSwatch(TIA::FixedColor::HBLANK_WHITE)
1016 << " HMOVE\n";
1017
1018 return buf.str();
1019}
1020
1021// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1022string TIADebug::palette() const
1023{
1024 ostringstream buf;
1025
1026 buf << " 0 2 4 6 8 A C E\n";
1027 uInt8 c = 0;
1028 for(uInt16 row = 0; row < 16; ++row)
1029 {
1030 buf << " " << Common::Base::HEX1 << row << " ";
1031 for(uInt16 col = 0; col < 8; ++col, c += 2)
1032 buf << colorSwatch(c);
1033
1034 buf << endl;
1035 }
1036 return buf.str();
1037}
1038
1039// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1040string TIADebug::toString()
1041{
1042 ostringstream buf;
1043
1044 buf << "00: ";
1045 for (uInt8 j = 0; j < 0x010; ++j)
1046 {
1047 buf << Common::Base::HEX2 << int(mySystem.peek(j)) << " ";
1048 if(j == 0x07) buf << "- ";
1049 }
1050 buf << endl;
1051
1052 // TODO: inverse video for changed regs. Core needs to track this.
1053 // TODO: strobes? WSYNC RSYNC RESP0/1 RESM0/1 RESBL HMOVE HMCLR CXCLR
1054
1055 const TiaState& state = static_cast<const TiaState&>(getState());
1056
1057 // build up output, then return it.
1058 buf << "scanline " << std::dec << myTIA.scanlines() << " "
1059 << booleanWithLabel("vsync", vsync()) << " "
1060 << booleanWithLabel("vblank", vblank())
1061 << endl
1062 << booleanWithLabel("inpt0", myTIA.peek(0x08) & 0x80) << " "
1063 << booleanWithLabel("inpt1", myTIA.peek(0x09) & 0x80) << " "
1064 << booleanWithLabel("inpt2", myTIA.peek(0x0a) & 0x80) << " "
1065 << booleanWithLabel("inpt3", myTIA.peek(0x0b) & 0x80) << " "
1066 << booleanWithLabel("inpt4", myTIA.peek(0x0c) & 0x80) << " "
1067 << booleanWithLabel("inpt5", myTIA.peek(0x0d) & 0x80) << " "
1068 << booleanWithLabel("dump_gnd_0123", myTIA.myPaddleReaders[0].vblankDumped())
1069 << endl
1070 << "COLUxx: "
1071 << "P0=$" << Common::Base::HEX2 << state.coluRegs[0] << "/"
1072 << colorSwatch(state.coluRegs[0])
1073 << " P1=$" << Common::Base::HEX2 << state.coluRegs[1] << "/"
1074 << colorSwatch(state.coluRegs[1])
1075 << " PF=$" << Common::Base::HEX2 << state.coluRegs[2] << "/"
1076 << colorSwatch(state.coluRegs[2])
1077 << " BK=$" << Common::Base::HEX2 << state.coluRegs[3] << "/"
1078 << colorSwatch(state.coluRegs[3])
1079 << endl
1080 << "P0: GR=%" << Common::Base::toString(state.gr[TiaState::P0], Common::Base::F_2_8)
1081 << " pos=#" << std::dec << state.pos[TiaState::P0]
1082 << " HM=$" << Common::Base::HEX2 << state.hm[TiaState::P0] << " "
1083 << nusizP0String() << " "
1084 << booleanWithLabel("refl", refP0()) << " "
1085 << booleanWithLabel("delay", vdelP0())
1086 << endl
1087 << "P1: GR=%" << Common::Base::toString(state.gr[TiaState::P1], Common::Base::F_2_8)
1088 << " pos=#" << std::dec << state.pos[TiaState::P1]
1089 << " HM=$" << Common::Base::HEX2 << state.hm[TiaState::P1] << " "
1090 << nusizP1String() << " "
1091 << booleanWithLabel("refl", refP1()) << " "
1092 << booleanWithLabel("delay", vdelP1())
1093 << endl
1094 << "M0: " << (enaM0() ? " ENABLED" : "disabled")
1095 << " pos=#" << std::dec << state.pos[TiaState::M0]
1096 << " HM=$" << Common::Base::HEX2 << state.hm[TiaState::M0]
1097 << " size=" << std::dec << state.size[TiaState::M0] << " "
1098 << booleanWithLabel("reset", resMP0())
1099 << endl
1100 << "M1: " << (enaM1() ? " ENABLED" : "disabled")
1101 << " pos=#" << std::dec << state.pos[TiaState::M1]
1102 << " HM=$" << Common::Base::HEX2 << state.hm[TiaState::M1]
1103 << " size=" << std::dec << state.size[TiaState::M1] << " "
1104 << booleanWithLabel("reset", resMP0())
1105 << endl
1106 << "BL: " << (enaBL() ? " ENABLED" : "disabled")
1107 << " pos=#" << std::dec << state.pos[TiaState::BL]
1108 << " HM=$" << Common::Base::HEX2 << state.hm[TiaState::BL]
1109 << " size=" << std::dec << state.size[TiaState::BL] << " "
1110 << booleanWithLabel("delay", vdelBL())
1111 << endl
1112 << "PF0: %" << Common::Base::toString(state.pf[0], Common::Base::F_2_8) << "/$"
1113 << Common::Base::HEX2 << state.pf[0]
1114 << " PF1: %" << Common::Base::toString(state.pf[1], Common::Base::F_2_8) << "/$"
1115 << Common::Base::HEX2 << state.pf[1]
1116 << " PF2: %" << Common::Base::toString(state.pf[2], Common::Base::F_2_8) << "/$"
1117 << Common::Base::HEX2 << state.pf[2]
1118 << endl << " "
1119 << booleanWithLabel("reflect", refPF()) << " "
1120 << booleanWithLabel("score", scorePF()) << " "
1121 << booleanWithLabel("priority", priorityPF())
1122 << endl
1123 << "Collisions: "
1124 << booleanWithLabel("m0_p1 ", collM0_P1())
1125 << booleanWithLabel("m0_p0 ", collM0_P0())
1126 << booleanWithLabel("m1_p0 ", collM1_P0())
1127 << booleanWithLabel("m1_p1 ", collM1_P1())
1128 << booleanWithLabel("p0_pf ", collP0_PF())
1129 << booleanWithLabel("p0_bl ", collP0_BL())
1130 << booleanWithLabel("p1_pf ", collP1_PF())
1131 << endl << " "
1132 << booleanWithLabel("p1_bl ", collP1_BL())
1133 << booleanWithLabel("m0_pf ", collM0_PF())
1134 << booleanWithLabel("m0_bl ", collM0_BL())
1135 << booleanWithLabel("m1_pf ", collM1_PF())
1136 << booleanWithLabel("m1_bl ", collM1_BL())
1137 << booleanWithLabel("bl_pf ", collBL_PF())
1138 << booleanWithLabel("p0_p1 ", collP0_P1())
1139 << endl << " "
1140 << booleanWithLabel("m0_m1 ", collM0_M1())
1141 << endl
1142 << "AUDF0: $" << Common::Base::HEX2 << int(audF0())
1143 << "/" << audFreq(audF0()) << " "
1144 << "AUDC0: $" << Common::Base::HEX2 << int(audC0()) << " "
1145 << "AUDV0: $" << Common::Base::HEX2 << int(audV0())
1146 << endl
1147 << "AUDF1: $" << Common::Base::HEX2 << int(audF1())
1148 << "/" << audFreq(audF1()) << " "
1149 << "AUDC1: $" << Common::Base::HEX2 << int(audC1()) << " "
1150 << "AUDV1: $" << Common::Base::HEX2 << int(audV1())
1151 ;
1152 // note: last line should not contain \n, caller will add.
1153 return buf.str();
1154}
1155
1156// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1157const std::array<string, 8> TIADebug::nusizStrings = {
1158 "1 copy",
1159 "2 copies - close (8)",
1160 "2 copies - med (24)",
1161 "3 copies - close (8)",
1162 "2 copies - wide (56)",
1163 "2x (16) sized player",
1164 "3 copies - med (24)",
1165 "4x (32) sized player"
1166};
1167