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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
23 | CartridgeCDFWidget::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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
194 | void 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
241 | void 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
373 | void 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
386 | string 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
400 | uInt32 CartridgeCDFWidget::internalRamSize() |
401 | { |
402 | return 8*1024; |
403 | } |
404 | |
405 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
406 | uInt32 CartridgeCDFWidget::internalRamRPort(int start) |
407 | { |
408 | return 0x0000 + start; |
409 | } |
410 | |
411 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
412 | string 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
427 | const 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
436 | const 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
445 | void CartridgeCDFWidget::internalRamSetValue(int addr, uInt8 value) |
446 | { |
447 | myCart.myCDFRAM[addr] = value; |
448 | } |
449 | |
450 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
451 | uInt8 CartridgeCDFWidget::internalRamGetValue(int addr) |
452 | { |
453 | return myCart.myCDFRAM[addr]; |
454 | } |
455 | |
456 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
457 | string 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
476 | bool CartridgeCDFWidget::isCDFJ() const |
477 | { |
478 | return myCart.myCDFSubtype == CartridgeCDF::CDFSubtype::CDFJ; |
479 | } |
480 | |