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