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