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 "DataGridWidget.hxx"
19#include "PopUpWidget.hxx"
20#include "CartCDFWidget.hxx"
21
22// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
23CartridgeCDFWidget::CartridgeCDFWidget(
24 GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
25 int x, int y, int w, int h, CartridgeCDF& cart)
26 : CartDebugWidget(boss, lfont, nfont, x, y, w, h),
27 myCart(cart)
28{
29 const int VBORDER = 8;
30 const int HBORDER = 2;
31 const int INDENT = 20;
32 const int VGAP = 4;
33
34 int xpos = HBORDER, ypos = VBORDER;
35
36 VariantList items;
37 VarList::push_back(items, "0 ($FFF5)");
38 VarList::push_back(items, "1 ($FFF6)");
39 VarList::push_back(items, "2 ($FFF7)");
40 VarList::push_back(items, "3 ($FFF8)");
41 VarList::push_back(items, "4 ($FFF9)");
42 VarList::push_back(items, "5 ($FFFA)");
43 VarList::push_back(items, "6 ($FFFB)");
44 myBank = new PopUpWidget(boss, _font, xpos, ypos, _font.getStringWidth("0 ($FFFx)"),
45 myLineHeight, items,
46 "Set bank ", 0, kBankChanged);
47 myBank->setTarget(this);
48 //addFocusWidget(myBank);
49
50 // Fast Fetch flag
51 myFastFetch = new CheckboxWidget(boss, _font, myBank->getRight() + 24, ypos + 1,
52 "Fast Fetcher enabled");
53 myFastFetch->setTarget(this);
54 myFastFetch->setEditable(false);
55
56 int lwidth;
57
58 // Datastream Pointers
59#define DS_X (HBORDER + _font.getStringWidth("xx "))
60 xpos = DS_X;
61 ypos += myLineHeight + VGAP * 4;
62 new StaticTextWidget(boss, _font, xpos, ypos, "Datastream Pointers");
63
64 myDatastreamPointers = new DataGridWidget(boss, _nfont, DS_X,
65 ypos+myLineHeight, 4, 8, 6, 32,
66 Common::Base::F_16_3_2);
67 myDatastreamPointers->setTarget(this);
68 myDatastreamPointers->setEditable(false);
69
70 myCommandStreamPointer = new DataGridWidget(boss, _nfont, DS_X + myDatastreamPointers->getWidth() * 3 / 4,
71 ypos+myLineHeight + 8*myLineHeight, 1, 1, 6, 32,
72 Common::Base::F_16_3_2);
73 myCommandStreamPointer->setTarget(this);
74 myCommandStreamPointer->setEditable(false);
75
76 if (isCDFJ())
77 myJumpStreamPointers = new DataGridWidget(boss, _nfont, DS_X + myDatastreamPointers->getWidth() * 2 / 4,
78 ypos+myLineHeight + 9*myLineHeight, 2, 1, 6, 32,
79 Common::Base::F_16_3_2);
80 else
81 myJumpStreamPointers = new DataGridWidget(boss, _nfont, DS_X + myDatastreamPointers->getWidth() * 3 / 4,
82 ypos+myLineHeight + 9*myLineHeight, 1, 1, 6, 32,
83 Common::Base::F_16_3_2);
84 myJumpStreamPointers->setTarget(this);
85 myJumpStreamPointers->setEditable(false);
86
87 uInt32 row;
88 for(row = 0; row < 8; ++row)
89 {
90 myDatastreamLabels[row] =
91 new StaticTextWidget(_boss, _font, DS_X - _font.getStringWidth("xx "),
92 ypos+myLineHeight + row*myLineHeight + 2, " ");
93 myDatastreamLabels[row]->setLabel(Common::Base::toString(row * 4,
94 Common::Base::F_16_2));
95 }
96 lwidth = _font.getStringWidth("Jump Data (21|22)");
97 myDatastreamLabels[8] =
98 new StaticTextWidget(_boss, _font, DS_X - _font.getStringWidth("xx "),
99 ypos+myLineHeight + 8*myLineHeight + 2,
100 lwidth, myFontHeight, "Write Data (20)");
101 myDatastreamLabels[9] =
102 new StaticTextWidget(_boss, _font, DS_X - _font.getStringWidth("xx "),
103 ypos+myLineHeight + 9*myLineHeight + 2,
104 lwidth, myFontHeight,
105 isCDFJ() ? "Jump Data (21|22)" : "Jump Data (21)");
106
107 // Datastream Increments
108 xpos = DS_X + myDatastreamPointers->getWidth() + 16;
109 new StaticTextWidget(boss, _font, xpos, ypos, "Datastream Increments");
110
111 myDatastreamIncrements = new DataGridWidget(boss, _nfont, xpos,
112 ypos+myLineHeight, 4, 8, 5, 32,
113 Common::Base::F_16_2_2);
114 myDatastreamIncrements->setTarget(this);
115 myDatastreamIncrements->setEditable(false);
116
117 myCommandStreamIncrement = new DataGridWidget(boss, _nfont, xpos,
118 ypos+myLineHeight + 8*myLineHeight, 1, 1, 5, 32,
119 Common::Base::F_16_2_2);
120 myCommandStreamIncrement->setTarget(this);
121 myCommandStreamIncrement->setEditable(false);
122
123 myJumpStreamIncrements = new DataGridWidget(boss, _nfont, xpos,
124 ypos+myLineHeight + 9*myLineHeight, isCDFJ() ? 2 : 1, 1, 5, 32,
125 Common::Base::F_16_2_2);
126 myJumpStreamIncrements->setTarget(this);
127 myJumpStreamIncrements->setEditable(false);
128 xpos = HBORDER; ypos += myLineHeight * 11 + VGAP * 4;
129
130 lwidth = _font.getStringWidth("Waveform Sizes ");
131
132 // Music counters
133 new StaticTextWidget(_boss, _font, xpos, ypos, "Music States:");
134 xpos += INDENT;
135 ypos += myLineHeight + VGAP;
136
137 new StaticTextWidget(boss, _font, xpos, ypos, "Counters");
138 xpos += lwidth;
139
140 myMusicCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32,
141 Common::Base::F_16_8);
142 myMusicCounters->setTarget(this);
143 myMusicCounters->setEditable(false);
144
145 // Music frequencies
146 xpos = HBORDER + INDENT; ypos += myLineHeight + VGAP;
147 new StaticTextWidget(boss, _font, xpos, ypos, "Frequencies");
148 xpos += lwidth;
149
150 myMusicFrequencies = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32,
151 Common::Base::F_16_8);
152 myMusicFrequencies->setTarget(this);
153 myMusicFrequencies->setEditable(false);
154
155 // Music waveforms
156 xpos = HBORDER + INDENT; ypos += myLineHeight + VGAP;
157 new StaticTextWidget(boss, _font, xpos, ypos, "Waveforms");
158 xpos += lwidth;
159
160 myMusicWaveforms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 16,
161 Common::Base::F_16_2);
162 myMusicWaveforms->setTarget(this);
163 myMusicWaveforms->setEditable(false);
164
165 // Music waveform sizes
166 xpos = HBORDER + INDENT; ypos += myLineHeight + VGAP;
167 new StaticTextWidget(boss, _font, xpos, ypos, "Waveform Sizes");
168 xpos += lwidth;
169
170 myMusicWaveformSizes = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 16,
171 Common::Base::F_16_2);
172 myMusicWaveformSizes->setTarget(this);
173 myMusicWaveformSizes->setEditable(false);
174
175 // Digital Audio flag
176 xpos = HBORDER; ypos += myLineHeight + VGAP;
177
178 myDigitalSample = new CheckboxWidget(boss, _font, xpos, ypos, "Digital Sample mode");
179 myDigitalSample->setTarget(this);
180 myDigitalSample->setEditable(false);
181
182 xpos = HBORDER + INDENT; ypos += myLineHeight + VGAP;
183
184 int lwidth2 = _font.getStringWidth("Sample Pointer ");
185 new StaticTextWidget(boss, _font, xpos, ypos, "Sample Pointer");
186
187 mySamplePointer = new DataGridWidget(boss, _nfont, xpos + lwidth2, ypos - 2, 1, 1, 8, 32,
188 Common::Base::F_16_8);
189 mySamplePointer->setTarget(this);
190 mySamplePointer->setEditable(false);
191}
192
193// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
194void CartridgeCDFWidget::saveOldState()
195{
196 myOldState.tops.clear();
197 myOldState.bottoms.clear();
198 myOldState.datastreampointers.clear();
199 myOldState.datastreamincrements.clear();
200 myOldState.addressmaps.clear();
201 myOldState.mcounters.clear();
202 myOldState.mfreqs.clear();
203 myOldState.mwaves.clear();
204 myOldState.mwavesizes.clear();
205 myOldState.internalram.clear();
206 myOldState.samplepointer.clear();
207
208 for(uInt32 i = 0; i < static_cast<uInt32>(isCDFJ() ? 35 : 34); ++i)
209 {
210 // Pointers are stored as:
211 // PPPFF---
212 //
213 // Increments are stored as
214 // ----IIFF
215 //
216 // P = Pointer
217 // I = Increment
218 // F = Fractional
219
220 myOldState.datastreampointers.push_back(myCart.getDatastreamPointer(i)>>12);
221 myOldState.datastreamincrements.push_back(myCart.getDatastreamIncrement(i));
222 }
223
224 for(uInt32 i = 0; i < 3; ++i)
225 myOldState.mcounters.push_back(myCart.myMusicCounters[i]);
226
227 for(uInt32 i = 0; i < 3; ++i)
228 {
229 myOldState.mfreqs.push_back(myCart.myMusicFrequencies[i]);
230 myOldState.mwaves.push_back(myCart.getWaveform(i) >> 5);
231 myOldState.mwavesizes.push_back(myCart.getWaveformSize((i)));
232 }
233
234 for(uInt32 i = 0; i < internalRamSize(); ++i)
235 myOldState.internalram.push_back(myCart.myCDFRAM[i]);
236
237 myOldState.samplepointer.push_back(myCart.getSample());
238}
239
240// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
241void CartridgeCDFWidget::loadConfig()
242{
243 myBank->setSelectedIndex(myCart.getBank());
244
245 // Get registers, using change tracking
246 IntArray alist;
247 IntArray vlist;
248 BoolArray changed;
249
250 alist.clear(); vlist.clear(); changed.clear();
251 for(int i = 0; i < 32; ++i)
252 {
253 // Pointers are stored as:
254 // PPPFF---
255 //
256 // Increments are stored as
257 // ----IIFF
258 //
259 // P = Pointer
260 // I = Increment
261 // F = Fractional
262
263 Int32 pointervalue = myCart.getDatastreamPointer(i) >> 12;
264 alist.push_back(0); vlist.push_back(pointervalue);
265 changed.push_back(pointervalue != myOldState.datastreampointers[i]);
266 }
267 myDatastreamPointers->setList(alist, vlist, changed);
268
269 alist.clear(); vlist.clear(); changed.clear();
270 for(int i = 32; i < 34; ++i)
271 {
272 Int32 pointervalue = myCart.getDatastreamPointer(i) >> 12;
273 alist.push_back(0); vlist.push_back(pointervalue);
274 changed.push_back(pointervalue != myOldState.datastreampointers[i]);
275 }
276
277 alist.clear(); vlist.clear(); changed.clear();
278 alist.push_back(0);
279 vlist.push_back(myCart.getDatastreamPointer(0x20) >> 12);
280 changed.push_back(static_cast<Int32>(myCart.getDatastreamPointer(0x20)) != myOldState.datastreampointers[0x20]);
281 myCommandStreamPointer->setList(alist, vlist, changed);
282
283 alist.clear(); vlist.clear(); changed.clear();
284 for(int i = 0; i < (isCDFJ() ? 2 : 1); ++i)
285 {
286 Int32 pointervalue = myCart.getDatastreamPointer(0x21 + i) >> 12;
287 alist.push_back(0); vlist.push_back(pointervalue);
288 changed.push_back(pointervalue != myOldState.datastreampointers[0x21 + i]);
289 }
290 myJumpStreamPointers->setList(alist, vlist, changed);
291
292 alist.clear(); vlist.clear(); changed.clear();
293 for(int i = 0; i < 32; ++i)
294 {
295 Int32 incrementvalue = myCart.getDatastreamIncrement(i);
296 alist.push_back(0); vlist.push_back(incrementvalue);
297 changed.push_back(incrementvalue != myOldState.datastreamincrements[i]);
298 }
299 myDatastreamIncrements->setList(alist, vlist, changed);
300
301 alist.clear(); vlist.clear(); changed.clear();
302 alist.push_back(0);
303 vlist.push_back(myCart.getDatastreamIncrement(0x20));
304 changed.push_back(static_cast<Int32>(myCart.getDatastreamIncrement(0x20)) != myOldState.datastreamincrements[0x20]);
305 myCommandStreamIncrement->setList(alist, vlist, changed);
306
307 alist.clear(); vlist.clear(); changed.clear();
308 for(int i = 0; i < (isCDFJ() ? 2 : 1); ++i)
309 {
310 Int32 pointervalue = myCart.getDatastreamIncrement(0x21 + i) >> 12;
311 alist.push_back(0); vlist.push_back(pointervalue);
312 changed.push_back(pointervalue != myOldState.datastreamincrements[0x21 + i]);
313 }
314 myJumpStreamIncrements->setList(alist, vlist, changed);
315
316 alist.clear(); vlist.clear(); changed.clear();
317 for(int i = 0; i < 3; ++i)
318 {
319 alist.push_back(0); vlist.push_back(myCart.myMusicCounters[i]);
320 changed.push_back(myCart.myMusicCounters[i] != uInt32(myOldState.mcounters[i]));
321 }
322 myMusicCounters->setList(alist, vlist, changed);
323
324 alist.clear(); vlist.clear(); changed.clear();
325 for(int i = 0; i < 3; ++i)
326 {
327 alist.push_back(0); vlist.push_back(myCart.myMusicFrequencies[i]);
328 changed.push_back(myCart.myMusicFrequencies[i] != uInt32(myOldState.mfreqs[i]));
329 }
330 myMusicFrequencies->setList(alist, vlist, changed);
331
332 alist.clear(); vlist.clear(); changed.clear();
333 for(int i = 0; i < 3; ++i)
334 {
335 alist.push_back(0); vlist.push_back(myCart.getWaveform(i) >> 5);
336 changed.push_back((myCart.getWaveform(i) >> 5) != uInt32(myOldState.mwaves[i]));
337 }
338 myMusicWaveforms->setList(alist, vlist, changed);
339
340 alist.clear(); vlist.clear(); changed.clear();
341 for(int i = 0; i < 3; ++i)
342 {
343 alist.push_back(0); vlist.push_back(myCart.getWaveformSize(i));
344 changed.push_back((myCart.getWaveformSize(i)) != uInt32(myOldState.mwavesizes[i]));
345 }
346 myMusicWaveformSizes->setList(alist, vlist, changed);
347
348 alist.clear(); vlist.clear(); changed.clear();
349 alist.push_back(0); vlist.push_back(myCart.getSample());
350 changed.push_back((myCart.getSample()) != uInt32(myOldState.samplepointer[0]));
351 mySamplePointer->setList(alist, vlist, changed);
352
353 myFastFetch->setState((myCart.myMode & 0x0f) == 0);
354 myDigitalSample->setState((myCart.myMode & 0xf0) == 0);
355
356 if ((myCart.myMode & 0xf0) == 0)
357 {
358 myMusicWaveforms->setCrossed(true);
359 myMusicWaveformSizes->setCrossed(true);
360 mySamplePointer->setCrossed(false);
361 }
362 else
363 {
364 myMusicWaveforms->setCrossed(false);
365 myMusicWaveformSizes->setCrossed(false);
366 mySamplePointer->setCrossed(true);
367 }
368
369 CartDebugWidget::loadConfig();
370}
371
372// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
373void CartridgeCDFWidget::handleCommand(CommandSender* sender,
374 int cmd, int data, int id)
375{
376 if(cmd == kBankChanged)
377 {
378 myCart.unlockBank();
379 myCart.bank(myBank->getSelected());
380 myCart.lockBank();
381 invalidate();
382 }
383}
384
385// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
386string CartridgeCDFWidget::bankState()
387{
388 ostringstream& buf = buffer();
389
390 static const char* const spot[] = {
391 "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
392 };
393 buf << "Bank = " << std::dec << myCart.getBank()
394 << ", hotspot = " << spot[myCart.getBank()];
395
396 return buf.str();
397}
398
399// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
400uInt32 CartridgeCDFWidget::internalRamSize()
401{
402 return 8*1024;
403}
404
405// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
406uInt32 CartridgeCDFWidget::internalRamRPort(int start)
407{
408 return 0x0000 + start;
409}
410
411// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
412string CartridgeCDFWidget::internalRamDescription()
413{
414 ostringstream desc;
415 desc << "$0000 - $07FF - CDF driver\n"
416 << " not accessible to 6507\n"
417 << "$0800 - $17FF - 4K Data Stream storage\n"
418 << " indirectly accessible to 6507\n"
419 << " via CDF's Data Stream registers\n"
420 << "$1800 - $1FFF - 2K C variable storage and stack\n"
421 << " not accessible to 6507";
422
423 return desc.str();
424}
425
426// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
427const ByteArray& CartridgeCDFWidget::internalRamOld(int start, int count)
428{
429 myRamOld.clear();
430 for(int i = 0; i < count; i++)
431 myRamOld.push_back(myOldState.internalram[start + i]);
432 return myRamOld;
433}
434
435// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
436const ByteArray& CartridgeCDFWidget::internalRamCurrent(int start, int count)
437{
438 myRamCurrent.clear();
439 for(int i = 0; i < count; i++)
440 myRamCurrent.push_back(myCart.myCDFRAM[start + i]);
441 return myRamCurrent;
442}
443
444// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
445void CartridgeCDFWidget::internalRamSetValue(int addr, uInt8 value)
446{
447 myCart.myCDFRAM[addr] = value;
448}
449
450// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
451uInt8 CartridgeCDFWidget::internalRamGetValue(int addr)
452{
453 return myCart.myCDFRAM[addr];
454}
455
456// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
457string CartridgeCDFWidget::describeCDFVersion(CartridgeCDF::CDFSubtype subtype)
458{
459 switch(subtype)
460 {
461 case CartridgeCDF::CDFSubtype::CDF0:
462 return "CDF (v0)";
463
464 case CartridgeCDF::CDFSubtype::CDF1:
465 return "CDF (v1)";
466
467 case CartridgeCDF::CDFSubtype::CDFJ:
468 return "CDFJ";
469
470 default:
471 throw runtime_error("unreachable");
472 }
473}
474
475// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
476bool CartridgeCDFWidget::isCDFJ() const
477{
478 return myCart.myCDFSubtype == CartridgeCDF::CDFSubtype::CDFJ;
479}
480