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-2014 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 // $Id: TIADebug.cxx 2838 2014-01-17 23:34:03Z stephena $
18 //============================================================================
19 
20 #include "Base.hxx"
21 #include "System.hxx"
22 #include "Debugger.hxx"
23 #include "TIA.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   nusizStrings[0] = "1 copy";
33   nusizStrings[1] = "2 copies - close (8)";
34   nusizStrings[2] = "2 copies - med (24)";
35   nusizStrings[3] = "3 copies - close (8)";
36   nusizStrings[4] = "2 copies - wide (56)";
37   nusizStrings[5] = "2x (16) sized player";
38   nusizStrings[6] = "3 copies - med (24)";
39   nusizStrings[7] = "4x (32) sized player";
40 }
41 
42 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
getState()43 const DebuggerState& TIADebug::getState()
44 {
45   myState.ram.clear();
46   for(int i = 0; i < 0x010; ++i)
47     myState.ram.push_back(myTIA.peek(i));
48 
49   // Color registers
50   myState.coluRegs.clear();
51   myState.coluRegs.push_back(coluP0());
52   myState.coluRegs.push_back(coluP1());
53   myState.coluRegs.push_back(coluPF());
54   myState.coluRegs.push_back(coluBK());
55 
56   // Player 1 & 2 graphics registers
57   myState.gr.clear();
58   myState.gr.push_back(grP0());
59   myState.gr.push_back(grP1());
60 
61   // Position registers
62   myState.pos.clear();
63   myState.pos.push_back(posP0());
64   myState.pos.push_back(posP1());
65   myState.pos.push_back(posM0());
66   myState.pos.push_back(posM1());
67   myState.pos.push_back(posBL());
68 
69   // Horizontal move registers
70   myState.hm.clear();
71   myState.hm.push_back(hmP0());
72   myState.hm.push_back(hmP1());
73   myState.hm.push_back(hmM0());
74   myState.hm.push_back(hmM1());
75   myState.hm.push_back(hmBL());
76 
77   // Playfield registers
78   myState.pf.clear();
79   myState.pf.push_back(pf0());
80   myState.pf.push_back(pf1());
81   myState.pf.push_back(pf2());
82 
83   // Size registers
84   myState.size.clear();
85   myState.size.push_back(nusizP0());
86   myState.size.push_back(nusizP1());
87   myState.size.push_back(nusizM0());
88   myState.size.push_back(nusizM1());
89   myState.size.push_back(sizeBL());
90 
91   // Audio registers
92   myState.aud.clear();
93   myState.aud.push_back(audF0());
94   myState.aud.push_back(audF1());
95   myState.aud.push_back(audC0());
96   myState.aud.push_back(audC1());
97   myState.aud.push_back(audV0());
98   myState.aud.push_back(audV1());
99 
100   return myState;
101 }
102 
103 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
saveOldState()104 void TIADebug::saveOldState()
105 {
106   myOldState.ram.clear();
107   for(int i = 0; i < 0x010; ++i)
108     myOldState.ram.push_back(myTIA.peek(i));
109 
110   // Color registers
111   myOldState.coluRegs.clear();
112   myOldState.coluRegs.push_back(coluP0());
113   myOldState.coluRegs.push_back(coluP1());
114   myOldState.coluRegs.push_back(coluPF());
115   myOldState.coluRegs.push_back(coluBK());
116 
117   // Player 1 & 2 graphics registers
118   myOldState.gr.clear();
119   myOldState.gr.push_back(grP0());
120   myOldState.gr.push_back(grP1());
121 
122   // Position registers
123   myOldState.pos.clear();
124   myOldState.pos.push_back(posP0());
125   myOldState.pos.push_back(posP1());
126   myOldState.pos.push_back(posM0());
127   myOldState.pos.push_back(posM1());
128   myOldState.pos.push_back(posBL());
129 
130   // Horizontal move registers
131   myOldState.hm.clear();
132   myOldState.hm.push_back(hmP0());
133   myOldState.hm.push_back(hmP1());
134   myOldState.hm.push_back(hmM0());
135   myOldState.hm.push_back(hmM1());
136   myOldState.hm.push_back(hmBL());
137 
138   // Playfield registers
139   myOldState.pf.clear();
140   myOldState.pf.push_back(pf0());
141   myOldState.pf.push_back(pf1());
142   myOldState.pf.push_back(pf2());
143 
144   // Size registers
145   myOldState.size.clear();
146   myOldState.size.push_back(nusizP0());
147   myOldState.size.push_back(nusizP1());
148   myOldState.size.push_back(nusizM0());
149   myOldState.size.push_back(nusizM1());
150   myOldState.size.push_back(sizeBL());
151 
152   // Audio registers
153   myOldState.aud.clear();
154   myOldState.aud.push_back(audF0());
155   myOldState.aud.push_back(audF1());
156   myOldState.aud.push_back(audC0());
157   myOldState.aud.push_back(audC1());
158   myOldState.aud.push_back(audV0());
159   myOldState.aud.push_back(audV1());
160 }
161 
162 /* the set methods now use mySystem.poke(). This will save us the
163    trouble of masking the values here, since TIA::poke() will do it
164    for us.
165 
166    This means that the GUI should *never* just display the value the
167    user entered: it should always read the return value of the set
168    method and display that.
169 
170    An Example:
171 
172    User enters "ff" in the AUDV0 field. GUI calls value = tiaDebug->audV0(0xff).
173    The AUDV0 register is only 4 bits wide, so "value" is 0x0f. That's what
174    should be displayed.
175 
176    In a perfect world, the GUI would only allow one hex digit to be entered...
177    but we allow decimal or binary input in the GUI (with # or \ prefix). The
178    only way to make that work would be to validate the data entry after every
179    keystroke... which would be a pain for both us and the user. Using poke()
180    here is a compromise that allows the TIA to do the range-checking for us,
181    so the GUI and/or TIADebug don't have to duplicate logic from TIA::poke().
182 */
183 
184 //   bool vdelP0(int newVal = -1);
185 //   bool vdelP1(int newVal = -1);
186 //   bool vdelBL(int newVal = -1);
187 
188 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
vdelP0(int newVal)189 bool TIADebug::vdelP0(int newVal)
190 {
191   if(newVal > -1)
192     mySystem.poke(VDELP0, ((bool)newVal));
193 
194   return myTIA.myVDELP0;
195 }
196 
197 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
vdelP1(int newVal)198 bool TIADebug::vdelP1(int newVal)
199 {
200   if(newVal > -1)
201     mySystem.poke(VDELP1, ((bool)newVal));
202 
203   return myTIA.myVDELP1;
204 }
205 
206 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
vdelBL(int newVal)207 bool TIADebug::vdelBL(int newVal)
208 {
209   if(newVal > -1)
210     mySystem.poke(VDELBL, ((bool)newVal));
211 
212   return myTIA.myVDELBL;
213 }
214 
215 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
enaM0(int newVal)216 bool TIADebug::enaM0(int newVal)
217 {
218   if(newVal > -1)
219     mySystem.poke(ENAM0, ((bool)newVal) << 1);
220 
221   return myTIA.myENAM0;
222 }
223 
224 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
enaM1(int newVal)225 bool TIADebug::enaM1(int newVal)
226 {
227   if(newVal > -1)
228     mySystem.poke(ENAM1, ((bool)newVal) << 1);
229 
230   return myTIA.myENAM1;
231 }
232 
233 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
enaBL(int newVal)234 bool TIADebug::enaBL(int newVal)
235 {
236   if(newVal > -1)
237     mySystem.poke(ENABL, ((bool)newVal) << 1);
238 
239   return myTIA.myENABL;
240 }
241 
242 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
resMP0(int newVal)243 bool TIADebug::resMP0(int newVal)
244 {
245   if(newVal > -1)
246     mySystem.poke(RESMP0, ((bool)newVal) << 1);
247 
248   return myTIA.myRESMP0;
249 }
250 
251 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
resMP1(int newVal)252 bool TIADebug::resMP1(int newVal)
253 {
254   if(newVal > -1)
255     mySystem.poke(RESMP1, ((bool)newVal) << 1);
256 
257   return myTIA.myRESMP1;
258 }
259 
260 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
refP0(int newVal)261 bool TIADebug::refP0(int newVal)
262 {
263   if(newVal > -1)
264     mySystem.poke(REFP0, ((bool)newVal) << 3);
265 
266   return myTIA.myREFP0;
267 }
268 
269 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
refP1(int newVal)270 bool TIADebug::refP1(int newVal)
271 {
272   if(newVal > -1)
273     mySystem.poke(REFP1, ((bool)newVal) << 3);
274 
275   return myTIA.myREFP1;
276 }
277 
278 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
refPF(int newVal)279 bool TIADebug::refPF(int newVal)
280 {
281   if(newVal > -1)
282   {
283     int tmp = myTIA.myCTRLPF;
284     if(newVal)
285       tmp |= 0x01;
286     else
287       tmp &= ~0x01;
288     mySystem.poke(CTRLPF, tmp);
289   }
290 
291   return myTIA.myCTRLPF & 0x01;
292 }
293 
294 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
scorePF(int newVal)295 bool TIADebug::scorePF(int newVal)
296 {
297   if(newVal > -1)
298   {
299     int tmp = myTIA.myCTRLPF;
300     if(newVal)
301       tmp |= 0x02;
302     else
303       tmp &= ~0x02;
304     mySystem.poke(CTRLPF, tmp);
305   }
306 
307   return myTIA.myCTRLPF & 0x02;
308 }
309 
310 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
priorityPF(int newVal)311 bool TIADebug::priorityPF(int newVal)
312 {
313   if(newVal > -1)
314   {
315     int tmp = myTIA.myCTRLPF;
316     if(newVal)
317       tmp |= 0x04;
318     else
319       tmp &= ~0x04;
320     mySystem.poke(CTRLPF, tmp);
321   }
322 
323   return myTIA.myCTRLPF & 0x04;
324 }
325 
326 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
collision(int collID,int newVal)327 bool TIADebug::collision(int collID, int newVal)
328 {
329   unsigned int mask = 1 << collID;
330 
331   if(newVal > -1)
332   {
333     if(newVal)
334       myTIA.myCollision |= mask;
335     else
336       myTIA.myCollision &= ~mask;
337   }
338 
339   return myTIA.myCollision & mask;
340 }
341 
342 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
audC0(int newVal)343 uInt8 TIADebug::audC0(int newVal)
344 {
345   if(newVal > -1)
346     mySystem.poke(AUDC0, newVal);
347 
348   return myTIA.myAUDC0;
349 }
350 
351 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
audC1(int newVal)352 uInt8 TIADebug::audC1(int newVal)
353 {
354   if(newVal > -1)
355     mySystem.poke(AUDC1, newVal);
356 
357   return myTIA.myAUDC1;
358 }
359 
360 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
audV0(int newVal)361 uInt8 TIADebug::audV0(int newVal)
362 {
363   if(newVal > -1)
364     mySystem.poke(AUDV0, newVal);
365 
366   return myTIA.myAUDV0;
367 }
368 
369 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
audV1(int newVal)370 uInt8 TIADebug::audV1(int newVal)
371 {
372   if(newVal > -1)
373     mySystem.poke(AUDV1, newVal);
374 
375   return myTIA.myAUDV1;
376 }
377 
378 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
audF0(int newVal)379 uInt8 TIADebug::audF0(int newVal)
380 {
381   if(newVal > -1)
382     mySystem.poke(AUDF0, newVal);
383 
384   return myTIA.myAUDF0;
385 }
386 
387 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
audF1(int newVal)388 uInt8 TIADebug::audF1(int newVal)
389 {
390   if(newVal > -1)
391     mySystem.poke(AUDF1, newVal);
392 
393   return myTIA.myAUDF1;
394 }
395 
396 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pf0(int newVal)397 uInt8 TIADebug::pf0(int newVal)
398 {
399   if(newVal > -1)
400     mySystem.poke(PF0, newVal << 4);
401 
402   return myTIA.myPF & 0x0f;
403 }
404 
405 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pf1(int newVal)406 uInt8 TIADebug::pf1(int newVal)
407 {
408   if(newVal > -1)
409     mySystem.poke(PF1, newVal);
410 
411   return (myTIA.myPF & 0xff0) >> 4;
412 }
413 
414 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pf2(int newVal)415 uInt8 TIADebug::pf2(int newVal)
416 {
417   if(newVal > -1)
418     mySystem.poke(PF2, newVal);
419 
420   return (myTIA.myPF & 0xff000) >> 12;
421 }
422 
423 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
coluP0(int newVal)424 uInt8 TIADebug::coluP0(int newVal)
425 {
426   if(newVal > -1)
427     mySystem.poke(COLUP0, newVal);
428 
429   return myTIA.myColor[P0Color] & 0xff;
430 }
431 
432 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
coluP1(int newVal)433 uInt8 TIADebug::coluP1(int newVal)
434 {
435   if(newVal > -1)
436     mySystem.poke(COLUP1, newVal);
437 
438   return myTIA.myColor[P1Color] & 0xff;
439 }
440 
441 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
coluPF(int newVal)442 uInt8 TIADebug::coluPF(int newVal)
443 {
444   if(newVal > -1)
445     mySystem.poke(COLUPF, newVal);
446 
447   return myTIA.myColor[PFColor] & 0xff;
448 }
449 
450 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
coluBK(int newVal)451 uInt8 TIADebug::coluBK(int newVal)
452 {
453   if(newVal > -1)
454     mySystem.poke(COLUBK, newVal);
455 
456   return myTIA.myColor[BKColor] & 0xff;
457 }
458 
459 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nusiz0(int newVal)460 uInt8 TIADebug::nusiz0(int newVal)
461 {
462   if(newVal > -1)
463     mySystem.poke(NUSIZ0, newVal);
464 
465   return myTIA.myNUSIZ0;
466 }
467 
468 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nusiz1(int newVal)469 uInt8 TIADebug::nusiz1(int newVal)
470 {
471   if(newVal > -1)
472     mySystem.poke(NUSIZ1, newVal);
473 
474   return myTIA.myNUSIZ1;
475 }
476 
477 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nusizP0(int newVal)478 uInt8 TIADebug::nusizP0(int newVal)
479 {
480   if(newVal > -1)
481   {
482     uInt8 tmp = myTIA.myNUSIZ0 & ~0x07;
483     tmp |= (newVal & 0x07);
484     mySystem.poke(NUSIZ0, tmp);
485   }
486 
487   return myTIA.myNUSIZ0 & 0x07;
488 }
489 
490 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nusizP1(int newVal)491 uInt8 TIADebug::nusizP1(int newVal)
492 {
493   if(newVal > -1)
494   {
495     uInt8 tmp = myTIA.myNUSIZ1 & ~0x07;
496     tmp |= newVal & 0x07;
497     mySystem.poke(NUSIZ1, tmp);
498   }
499 
500   return myTIA.myNUSIZ1 & 0x07;
501 }
502 
503 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nusizM0(int newVal)504 uInt8 TIADebug::nusizM0(int newVal)
505 {
506   if(newVal > -1)
507   {
508     uInt8 tmp = myTIA.myNUSIZ0 & ~0x30;
509     tmp |= (newVal & 0x04) << 4;
510     mySystem.poke(NUSIZ0, tmp);
511   }
512 
513   return (myTIA.myNUSIZ0 & 0x30) >> 4;
514 }
515 
516 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nusizM1(int newVal)517 uInt8 TIADebug::nusizM1(int newVal)
518 {
519   if(newVal > -1)
520   {
521     uInt8 tmp = myTIA.myNUSIZ1 & ~0x30;
522     tmp |= (newVal & 0x04) << 4;
523     mySystem.poke(NUSIZ1, tmp);
524   }
525 
526   return (myTIA.myNUSIZ1 & 0x30) >> 4;
527 }
528 
529 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
grP0(int newVal)530 uInt8 TIADebug::grP0(int newVal)
531 {
532   if(newVal > -1)
533     mySystem.poke(GRP0, newVal);
534 
535   return myTIA.myGRP0;
536 }
537 
538 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
grP1(int newVal)539 uInt8 TIADebug::grP1(int newVal)
540 {
541   if(newVal > -1)
542     mySystem.poke(GRP1, newVal);
543 
544   return myTIA.myGRP1;
545 }
546 
547 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
posP0(int newVal)548 uInt8 TIADebug::posP0(int newVal)
549 {
550   if(newVal > -1)
551     myTIA.myPOSP0 = newVal;
552 
553   return myTIA.myPOSP0;
554 }
555 
556 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
posP1(int newVal)557 uInt8 TIADebug::posP1(int newVal)
558 {
559   if(newVal > -1)
560     myTIA.myPOSP1 = newVal;
561 
562   return myTIA.myPOSP1;
563 }
564 
565 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
posM0(int newVal)566 uInt8 TIADebug::posM0(int newVal)
567 {
568   if(newVal > -1)
569     myTIA.myPOSM0 = newVal;
570 
571   return myTIA.myPOSM0;
572 }
573 
574 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
posM1(int newVal)575 uInt8 TIADebug::posM1(int newVal)
576 {
577   if(newVal > -1)
578     myTIA.myPOSM1 = newVal;
579 
580   return myTIA.myPOSM1;
581 }
582 
583 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
posBL(int newVal)584 uInt8 TIADebug::posBL(int newVal)
585 {
586   if(newVal > -1)
587     myTIA.myPOSBL = newVal;
588 
589   return myTIA.myPOSBL;
590 }
591 
592 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ctrlPF(int newVal)593 uInt8 TIADebug::ctrlPF(int newVal)
594 {
595   if(newVal > -1)
596     mySystem.poke(CTRLPF, newVal);
597 
598   return myTIA.myCTRLPF;
599 }
600 
601 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sizeBL(int newVal)602 uInt8 TIADebug::sizeBL(int newVal)
603 {
604   if(newVal > -1)
605   {
606     uInt8 tmp = myTIA.myCTRLPF & ~0x30;
607     tmp |= (newVal & 0x04) << 4;
608     mySystem.poke(CTRLPF, tmp);
609   }
610 
611   return (myTIA.myCTRLPF & 0x30) >> 4;
612 }
613 
614 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
hmP0(int newVal)615 uInt8 TIADebug::hmP0(int newVal)
616 {
617   if(newVal > -1)
618     mySystem.poke(HMP0, newVal << 4);
619 
620   return myTIA.myHMP0 >> 4;
621 }
622 
623 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
hmP1(int newVal)624 uInt8 TIADebug::hmP1(int newVal)
625 {
626   if(newVal > -1)
627     mySystem.poke(HMP1, newVal << 4);
628 
629   return myTIA.myHMP1 >> 4;
630 }
631 
632 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
hmM0(int newVal)633 uInt8 TIADebug::hmM0(int newVal)
634 {
635   if(newVal > -1)
636     mySystem.poke(HMM0, newVal << 4);
637 
638   return myTIA.myHMM0 >> 4;
639 }
640 
641 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
hmM1(int newVal)642 uInt8 TIADebug::hmM1(int newVal)
643 {
644   if(newVal > -1)
645     mySystem.poke(HMM1, newVal << 4);
646 
647   return myTIA.myHMM1 >> 4;
648 }
649 
650 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
hmBL(int newVal)651 uInt8 TIADebug::hmBL(int newVal)
652 {
653   if(newVal > -1)
654     mySystem.poke(HMBL, newVal << 4);
655 
656   return myTIA.myHMBL >> 4;
657 }
658 
659 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
frameCount()660 int TIADebug::frameCount()
661 {
662   return myTIA.myFrameCounter;
663 }
664 
665 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
scanlines()666 int TIADebug::scanlines()
667 {
668   return myTIA.scanlines();
669 }
670 
671 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
clocksThisLine()672 int TIADebug::clocksThisLine()
673 {
674   return myTIA.clocksThisLine();
675 }
676 
677 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
vsync()678 bool TIADebug::vsync()
679 {
680   return (myTIA.myVSYNC & 2) == 2;
681 }
682 
683 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
vblank()684 bool TIADebug::vblank()
685 {
686   return (myTIA.myVBLANK & 2) == 2;
687 }
688 
689 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
colorSwatch(uInt8 c)690 string TIADebug::colorSwatch(uInt8 c)
691 {
692   string ret;
693 
694   ret += char((c >> 1) | 0x80);
695   ret += "\177     ";
696   ret += "\177\003 ";
697 
698   return ret;
699 }
700 
701 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
audFreq(uInt8 div)702 string TIADebug::audFreq(uInt8 div)
703 {
704   string ret;
705   char buf[10];
706 
707   double hz = 30000.0;
708   if(div) hz /= div;
709   BSPF_snprintf(buf, 9, "%5.1f", hz);
710   ret += buf;
711   ret += "Hz";
712 
713   return ret;
714 }
715 
716 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
booleanWithLabel(string label,bool value)717 string TIADebug::booleanWithLabel(string label, bool value)
718 {
719   char buf[64];
720   string ret;
721 
722   if(value)
723   {
724     char *p = buf;
725     const char *q = label.c_str();
726     while((*p++ = toupper(*q++)))
727       ;
728     ret += "+";
729     ret += buf;
730     return ret;
731   }
732   else
733     return "-" + label;
734 }
735 
736 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
toString()737 string TIADebug::toString()
738 {
739   ostringstream buf;
740 
741   buf << "00: ";
742   for (uInt8 j = 0; j < 0x010; j++)
743   {
744     buf << Common::Base::HEX2 << (int)mySystem.peek(j) << " ";
745     if(j == 0x07) buf << "- ";
746   }
747   buf << endl;
748 
749   // TODO: inverse video for changed regs. Core needs to track this.
750   // TODO: strobes? WSYNC RSYNC RESP0/1 RESM0/1 RESBL HMOVE HMCLR CXCLR
751 
752   const TiaState& state    = (TiaState&) getState();
753 //  const TiaState& oldstate = (TiaState&) getOldState();
754 
755   // build up output, then return it.
756   buf << "scanline " << dec << myTIA.scanlines() << " "
757       << booleanWithLabel("vsync", vsync()) << " "
758       << booleanWithLabel("vblank", vblank())
759       << endl
760       << booleanWithLabel("inpt0", myTIA.peek(0x08) & 0x80) << " "
761       << booleanWithLabel("inpt1", myTIA.peek(0x09) & 0x80) << " "
762       << booleanWithLabel("inpt2", myTIA.peek(0x0a) & 0x80) << " "
763       << booleanWithLabel("inpt3", myTIA.peek(0x0b) & 0x80) << " "
764       << booleanWithLabel("inpt4", myTIA.peek(0x0c) & 0x80) << " "
765       << booleanWithLabel("inpt5", myTIA.peek(0x0d) & 0x80) << " "
766       << booleanWithLabel("dump_gnd_0123", myTIA.myDumpEnabled)
767       << endl
768       << "COLUxx: "
769       << "P0=$" << Common::Base::HEX2 << state.coluRegs[0] << "/"
770       << colorSwatch(state.coluRegs[0])
771       << "P1=$" << Common::Base::HEX2 << state.coluRegs[1] << "/"
772       << colorSwatch(state.coluRegs[1])
773       << "PF=$" << Common::Base::HEX2 << state.coluRegs[2] << "/"
774       << colorSwatch(state.coluRegs[2])
775       << "BK=$" << Common::Base::HEX2 << state.coluRegs[3] << "/"
776       << colorSwatch(state.coluRegs[3])
777       << endl
778       << "P0: GR=%" << Common::Base::toString(state.gr[P0], Common::Base::F_2_8)
779       << " pos=#" << dec << state.pos[P0]
780       << " HM=$" << Common::Base::HEX2 << state.hm[P0] << " "
781       << nusizP0String() << " "
782       << booleanWithLabel("refl", refP0()) << " "
783       << booleanWithLabel("delay", vdelP0())
784       << endl
785       << "P1: GR=%" << Common::Base::toString(state.gr[P1], Common::Base::F_2_8)
786       << " pos=#" << dec << state.pos[P1]
787       << " HM=$" << Common::Base::HEX2 << state.hm[P1] << " "
788       << nusizP1String() << " "
789       << booleanWithLabel("refl", refP1()) << " "
790       << booleanWithLabel("delay", vdelP1())
791       << endl
792       << "M0: " << (myTIA.myENAM0 ? " ENABLED" : "disabled")
793       << " pos=#" << dec << state.pos[M0]
794       << " HM=$" << Common::Base::HEX2 << state.hm[M0]
795       << " size=" << dec << state.size[M0] << " "
796       << booleanWithLabel("reset", resMP0())
797       << endl
798       << "M1: " << (myTIA.myENAM1 ? " ENABLED" : "disabled")
799       << " pos=#" << dec << state.pos[M1]
800       << " HM=$" << Common::Base::HEX2 << state.hm[M1]
801       << " size=" << dec << state.size[M1] << " "
802       << booleanWithLabel("reset", resMP0())
803       << endl
804       << "BL: " << (myTIA.myENABL ? " ENABLED" : "disabled")
805       << " pos=#" << dec << state.pos[BL]
806       << " HM=$" << Common::Base::HEX2 << state.hm[BL]
807       << " size=" << dec << state.size[BL] << " "
808       << booleanWithLabel("delay", vdelBL())
809       << endl
810       << "PF0: %" << Common::Base::toString(state.pf[0], Common::Base::F_2_8) << "/$"
811       << Common::Base::HEX2 << state.pf[0]
812       << " PF1: %" << Common::Base::toString(state.pf[1], Common::Base::F_2_8) << "/$"
813       << Common::Base::HEX2 << state.pf[1]
814       << " PF2: %" << Common::Base::toString(state.pf[2], Common::Base::F_2_8) << "/$"
815       << Common::Base::HEX2 << state.pf[2]
816       << endl << "     "
817       << booleanWithLabel("reflect",  refPF()) << " "
818       << booleanWithLabel("score",    scorePF()) << " "
819       << booleanWithLabel("priority", priorityPF())
820       << endl
821       << "Collisions: "
822       << booleanWithLabel("m0_p1 ", collM0_P1())
823       << booleanWithLabel("m0_p0 ", collM0_P0())
824       << booleanWithLabel("m1_p0 ", collM1_P0())
825       << booleanWithLabel("m1_p1 ", collM1_P1())
826       << booleanWithLabel("p0_pf ", collP0_PF())
827       << booleanWithLabel("p0_bl ", collP0_BL())
828       << booleanWithLabel("p1_pf ", collP1_PF())
829       << endl << "            "
830       << booleanWithLabel("p1_bl ", collP1_BL())
831       << booleanWithLabel("m0_pf ", collM0_PF())
832       << booleanWithLabel("m0_bl ", collM0_BL())
833       << booleanWithLabel("m1_pf ", collM1_PF())
834       << booleanWithLabel("m1_bl ", collM1_BL())
835       << booleanWithLabel("bl_pf ", collBL_PF())
836       << booleanWithLabel("p0_p1 ", collP0_P1())
837       << endl << "            "
838       << booleanWithLabel("m0_m1 ", collM0_M1())
839       << endl
840       << "AUDF0: $" << Common::Base::HEX2 << (int)myTIA.myAUDF0
841       << "/" << audFreq(myTIA.myAUDF0) << " "
842       << "AUDC0: $" << Common::Base::HEX2 << (int)myTIA.myAUDC0 << " "
843       << "AUDV0: $" << Common::Base::HEX2 << (int)myTIA.myAUDV0
844       << endl
845       << "AUDF1: $" << Common::Base::HEX2 << (int)myTIA.myAUDF1
846       << "/" << audFreq(myTIA.myAUDF1) << " "
847       << "AUDC1: $" << Common::Base::HEX2 << (int)myTIA.myAUDC1 << " "
848       << "AUDV1: $" << Common::Base::HEX2 << (int)myTIA.myAUDV1
849       ;
850   // note: last line should not contain \n, caller will add.
851   return buf.str();
852 }
853