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 "CartDPCPlus.hxx"
19#include "DataGridWidget.hxx"
20#include "PopUpWidget.hxx"
21#include "CartDPCPlusWidget.hxx"
22
23// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
24CartridgeDPCPlusWidget::CartridgeDPCPlusWidget(
25 GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
26 int x, int y, int w, int h, CartridgeDPCPlus& cart)
27 : CartDebugWidget(boss, lfont, nfont, x, y, w, h),
28 myCart(cart)
29{
30 size_t size = cart.mySize;
31
32 ostringstream info;
33 info << "Extended DPC cartridge, six 4K banks, 4K display bank, 1K frequency table, "
34 << "8K DPC RAM\n"
35 << "DPC registers accessible @ $F000 - $F07F\n"
36 << " $F000 - $F03F (R), $F040 - $F07F (W)\n"
37 << "Banks accessible at hotspots $FFF6 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 = 0xFF6; i < 6; ++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, "Activision (Pitfall II)", info.str()) +
53 myLineHeight;
54
55 VariantList items;
56 VarList::push_back(items, "0 ($FFF6)");
57 VarList::push_back(items, "1 ($FFF7)");
58 VarList::push_back(items, "2 ($FFF8)");
59 VarList::push_back(items, "3 ($FFF9)");
60 VarList::push_back(items, "4 ($FFFA)");
61 VarList::push_back(items, "5 ($FFFB)");
62 myBank =
63 new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx)"),
64 myLineHeight, items, "Set bank ",
65 0, kBankChanged);
66 myBank->setTarget(this);
67 addFocusWidget(myBank);
68
69 // Top registers
70 int lwidth = _font.getStringWidth("Counter Registers ");
71 xpos = 2; ypos += myLineHeight + 8;
72 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
73 myFontHeight, "Top Registers ", TextAlign::Left);
74 xpos += lwidth;
75
76 myTops = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::F_16);
77 myTops->setTarget(this);
78 myTops->setEditable(false);
79
80 // Bottom registers
81 xpos = 2; ypos += myLineHeight + 4;
82 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
83 myFontHeight, "Bottom Registers ", TextAlign::Left);
84 xpos += lwidth;
85
86 myBottoms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::F_16);
87 myBottoms->setTarget(this);
88 myBottoms->setEditable(false);
89
90 // Counter registers
91 xpos = 2; ypos += myLineHeight + 4;
92 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
93 myFontHeight, "Counter Registers ", TextAlign::Left);
94 xpos += lwidth;
95
96 myCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 4, 16, Common::Base::F_16_4);
97 myCounters->setTarget(this);
98 myCounters->setEditable(false);
99
100 // Fractional counter registers
101 xpos = 2; ypos += myLineHeight + 4;
102 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
103 myFontHeight, "Frac Counters ", TextAlign::Left);
104 xpos += lwidth;
105
106 myFracCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 4, 2, 8, 32, Common::Base::F_16_8);
107 myFracCounters->setTarget(this);
108 myFracCounters->setEditable(false);
109
110 // Fractional increment registers
111 xpos = 2; ypos += myFracCounters->getHeight() + 8;
112 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
113 myFontHeight, "Frac Increments ", TextAlign::Left);
114 xpos += lwidth;
115
116 myFracIncrements = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::F_16);
117 myFracIncrements->setTarget(this);
118 myFracIncrements->setEditable(false);
119
120 // Special function parameters
121 xpos = 2; ypos += myLineHeight + 4;
122 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
123 myFontHeight, "Function Params ", TextAlign::Left);
124 xpos += lwidth;
125
126 myParameter = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::F_16);
127 myParameter->setTarget(this);
128 myParameter->setEditable(false);
129
130 // Music counters
131 xpos = 2; ypos += myLineHeight + 4;
132 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
133 myFontHeight, "Music Counters ", TextAlign::Left);
134 xpos += lwidth;
135
136 myMusicCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::F_16_8);
137 myMusicCounters->setTarget(this);
138 myMusicCounters->setEditable(false);
139
140 // Music frequencies
141 xpos = 2; ypos += myLineHeight + 4;
142 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
143 myFontHeight, "Music Frequencies ", TextAlign::Left);
144 xpos += lwidth;
145
146 myMusicFrequencies = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::F_16_8);
147 myMusicFrequencies->setTarget(this);
148 myMusicFrequencies->setEditable(false);
149
150 // Music waveforms
151 xpos = 2; ypos += myLineHeight + 4;
152 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
153 myFontHeight, "Music Waveforms ", TextAlign::Left);
154 xpos += lwidth;
155
156 myMusicWaveforms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 4, 16, Common::Base::F_16_4);
157 myMusicWaveforms->setTarget(this);
158 myMusicWaveforms->setEditable(false);
159
160 // Current random number
161 lwidth = _font.getStringWidth("Current random number ");
162 xpos = 2; ypos += myLineHeight + 4;
163 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
164 myFontHeight, "Current random number ", TextAlign::Left);
165 xpos += lwidth;
166
167 myRandom = new DataGridWidget(boss, _nfont, xpos, ypos-2, 1, 1, 8, 32, Common::Base::F_16_8);
168 myRandom->setTarget(this);
169 myRandom->setEditable(false);
170
171 // Fast fetch and immediate mode LDA flags
172 xpos += myRandom->getWidth() + 30;
173 myFastFetch = new CheckboxWidget(boss, _font, xpos, ypos, "Fast Fetcher enabled");
174 myFastFetch->setTarget(this);
175 myFastFetch->setEditable(false);
176 ypos += myLineHeight + 4;
177 myIMLDA = new CheckboxWidget(boss, _font, xpos, ypos, "Immediate mode LDA");
178 myIMLDA->setTarget(this);
179 myIMLDA->setEditable(false);
180}
181
182// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
183void CartridgeDPCPlusWidget::saveOldState()
184{
185 myOldState.tops.clear();
186 myOldState.bottoms.clear();
187 myOldState.counters.clear();
188 myOldState.fraccounters.clear();
189 myOldState.fracinc.clear();
190 myOldState.param.clear();
191 myOldState.mcounters.clear();
192 myOldState.mfreqs.clear();
193 myOldState.mwaves.clear();
194 myOldState.internalram.clear();
195
196 for(uInt32 i = 0; i < 8; ++i)
197 {
198 myOldState.tops.push_back(myCart.myTops[i]);
199 myOldState.bottoms.push_back(myCart.myBottoms[i]);
200 myOldState.counters.push_back(myCart.myCounters[i]);
201 myOldState.fraccounters.push_back(myCart.myFractionalCounters[i]);
202 myOldState.fracinc.push_back(myCart.myFractionalIncrements[i]);
203 myOldState.param.push_back(myCart.myParameter[i]);
204 }
205 for(uInt32 i = 0; i < 3; ++i)
206 {
207 myOldState.mcounters.push_back(myCart.myMusicCounters[i]);
208 myOldState.mfreqs.push_back(myCart.myMusicFrequencies[i]);
209 myOldState.mwaves.push_back(myCart.myMusicWaveforms[i]);
210 }
211
212 myOldState.random = myCart.myRandomNumber;
213
214 for(uInt32 i = 0; i < internalRamSize(); ++i)
215 myOldState.internalram.push_back(myCart.myDisplayImage[i]);
216
217 myOldState.bank = myCart.getBank();
218}
219
220// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
221void CartridgeDPCPlusWidget::loadConfig()
222{
223 myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank);
224
225 // Get registers, using change tracking
226 IntArray alist;
227 IntArray vlist;
228 BoolArray changed;
229
230 alist.clear(); vlist.clear(); changed.clear();
231 for(int i = 0; i < 8; ++i)
232 {
233 alist.push_back(0); vlist.push_back(myCart.myTops[i]);
234 changed.push_back(myCart.myTops[i] != myOldState.tops[i]);
235 }
236 myTops->setList(alist, vlist, changed);
237
238 alist.clear(); vlist.clear(); changed.clear();
239 for(int i = 0; i < 8; ++i)
240 {
241 alist.push_back(0); vlist.push_back(myCart.myBottoms[i]);
242 changed.push_back(myCart.myBottoms[i] != myOldState.bottoms[i]);
243 }
244 myBottoms->setList(alist, vlist, changed);
245
246 alist.clear(); vlist.clear(); changed.clear();
247 for(int i = 0; i < 8; ++i)
248 {
249 alist.push_back(0); vlist.push_back(myCart.myCounters[i]);
250 changed.push_back(myCart.myCounters[i] != myOldState.counters[i]);
251 }
252 myCounters->setList(alist, vlist, changed);
253
254 alist.clear(); vlist.clear(); changed.clear();
255 for(int i = 0; i < 8; ++i)
256 {
257 alist.push_back(0); vlist.push_back(myCart.myFractionalCounters[i]);
258 changed.push_back(myCart.myFractionalCounters[i] != uInt32(myOldState.fraccounters[i]));
259 }
260 myFracCounters->setList(alist, vlist, changed);
261
262 alist.clear(); vlist.clear(); changed.clear();
263 for(int i = 0; i < 8; ++i)
264 {
265 alist.push_back(0); vlist.push_back(myCart.myFractionalIncrements[i]);
266 changed.push_back(myCart.myFractionalIncrements[i] != myOldState.fracinc[i]);
267 }
268 myFracIncrements->setList(alist, vlist, changed);
269
270 alist.clear(); vlist.clear(); changed.clear();
271 for(int i = 0; i < 8; ++i)
272 {
273 alist.push_back(0); vlist.push_back(myCart.myParameter[i]);
274 changed.push_back(myCart.myParameter[i] != myOldState.param[i]);
275 }
276 myParameter->setList(alist, vlist, changed);
277
278 alist.clear(); vlist.clear(); changed.clear();
279 for(int i = 0; i < 3; ++i)
280 {
281 alist.push_back(0); vlist.push_back(myCart.myMusicCounters[i]);
282 changed.push_back(myCart.myMusicCounters[i] != uInt32(myOldState.mcounters[i]));
283 }
284 myMusicCounters->setList(alist, vlist, changed);
285
286 alist.clear(); vlist.clear(); changed.clear();
287 for(int i = 0; i < 3; ++i)
288 {
289 alist.push_back(0); vlist.push_back(myCart.myMusicFrequencies[i]);
290 changed.push_back(myCart.myMusicFrequencies[i] != uInt32(myOldState.mfreqs[i]));
291 }
292 myMusicFrequencies->setList(alist, vlist, changed);
293
294 alist.clear(); vlist.clear(); changed.clear();
295 for(int i = 0; i < 3; ++i)
296 {
297 alist.push_back(0); vlist.push_back(myCart.myMusicWaveforms[i]);
298 changed.push_back(myCart.myMusicWaveforms[i] != myOldState.mwaves[i]);
299 }
300 myMusicWaveforms->setList(alist, vlist, changed);
301
302 myRandom->setList(0, myCart.myRandomNumber,
303 myCart.myRandomNumber != myOldState.random);
304
305 myFastFetch->setState(myCart.myFastFetch);
306 myIMLDA->setState(myCart.myLDAimmediate);
307
308 CartDebugWidget::loadConfig();
309}
310
311// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
312void CartridgeDPCPlusWidget::handleCommand(CommandSender* sender,
313 int cmd, int data, int id)
314{
315 if(cmd == kBankChanged)
316 {
317 myCart.unlockBank();
318 myCart.bank(myBank->getSelected());
319 myCart.lockBank();
320 invalidate();
321 }
322}
323
324// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
325string CartridgeDPCPlusWidget::bankState()
326{
327 ostringstream& buf = buffer();
328
329 static const char* const spot[] = {
330 "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
331 };
332 buf << "Bank = " << std::dec << myCart.getBank()
333 << ", hotspot = " << spot[myCart.getBank()];
334
335 return buf.str();
336}
337
338// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
339uInt32 CartridgeDPCPlusWidget::internalRamSize()
340{
341 return 5*1024;
342}
343
344// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
345uInt32 CartridgeDPCPlusWidget::internalRamRPort(int start)
346{
347 return 0x0000 + start;
348}
349
350// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
351string CartridgeDPCPlusWidget::internalRamDescription()
352{
353 ostringstream desc;
354 desc << "$0000 - $0FFF - 4K display data\n"
355 << " indirectly accessible to 6507\n"
356 << " via DPC+'s Data Fetcher registers\n"
357 << "$1000 - $13FF - 1K frequency table,\n"
358 << " C variables and C stack\n"
359 << " not accessible to 6507";
360
361 return desc.str();
362}
363
364// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
365const ByteArray& CartridgeDPCPlusWidget::internalRamOld(int start, int count)
366{
367 myRamOld.clear();
368 for(int i = 0; i < count; i++)
369 myRamOld.push_back(myOldState.internalram[start + i]);
370 return myRamOld;
371}
372
373// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
374const ByteArray& CartridgeDPCPlusWidget::internalRamCurrent(int start, int count)
375{
376 myRamCurrent.clear();
377 for(int i = 0; i < count; i++)
378 myRamCurrent.push_back(myCart.myDisplayImage[start + i]);
379 return myRamCurrent;
380}
381
382// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
383void CartridgeDPCPlusWidget::internalRamSetValue(int addr, uInt8 value)
384{
385 myCart.myDisplayImage[addr] = value;
386}
387
388// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
389uInt8 CartridgeDPCPlusWidget::internalRamGetValue(int addr)
390{
391 return myCart.myDisplayImage[addr];
392}
393