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 "CartDPC.hxx"
19#include "DataGridWidget.hxx"
20#include "PopUpWidget.hxx"
21#include "CartDPCWidget.hxx"
22
23// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
24CartridgeDPCWidget::CartridgeDPCWidget(
25 GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
26 int x, int y, int w, int h, CartridgeDPC& 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 << "DPC cartridge, two 4K banks + 2K display bank\n"
34 << "DPC registers accessible @ $F000 - $F07F\n"
35 << " $F000 - $F03F (R), $F040 - $F07F (W)\n"
36
37 << "Startup bank = " << cart.startBank() << " or undetermined\n";
38
39 // Eventually, we should query this from the debugger/disassembler
40 for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF8; i < 2; ++i, offset += 0x1000)
41 {
42 uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset];
43 start -= start % 0x1000;
44 info << "Bank " << i << " @ $" << Common::Base::HEX4 << (start + 0x80) << " - "
45 << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n";
46 }
47
48 int xpos = 2,
49 ypos = addBaseInformation(size, "Activision (Pitfall II)", info.str()) +
50 myLineHeight;
51
52 VariantList items;
53 VarList::push_back(items, "0 ($FFF8)");
54 VarList::push_back(items, "1 ($FFF9)");
55 myBank =
56 new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx)"),
57 myLineHeight, items, "Set bank ",
58 0, kBankChanged);
59 myBank->setTarget(this);
60 addFocusWidget(myBank);
61 ypos += myLineHeight + 8;
62
63 // Data fetchers
64 int lwidth = _font.getStringWidth("Data Fetchers ");
65 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
66 myFontHeight, "Data Fetchers ", TextAlign::Left);
67
68 // Top registers
69 lwidth = _font.getStringWidth("Counter Registers ");
70 xpos = 18; ypos += myLineHeight + 4;
71 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
72 myFontHeight, "Top Registers ", TextAlign::Left);
73 xpos += lwidth;
74
75 myTops = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::F_16);
76 myTops->setTarget(this);
77 myTops->setEditable(false);
78
79 // Bottom registers
80 xpos = 10; ypos += myLineHeight + 4;
81 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
82 myFontHeight, "Bottom Registers ", TextAlign::Left);
83 xpos += lwidth;
84
85 myBottoms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::F_16);
86 myBottoms->setTarget(this);
87 myBottoms->setEditable(false);
88
89 // Counter registers
90 xpos = 10; ypos += myLineHeight + 4;
91 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
92 myFontHeight, "Counter Registers ", TextAlign::Left);
93 xpos += lwidth;
94
95 myCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 4, 16, Common::Base::F_16_4);
96 myCounters->setTarget(this);
97 myCounters->setEditable(false);
98
99 // Flag registers
100 xpos = 10; ypos += myLineHeight + 4;
101 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
102 myFontHeight, "Flag Registers ", TextAlign::Left);
103 xpos += lwidth;
104
105 myFlags = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::F_16);
106 myFlags->setTarget(this);
107 myFlags->setEditable(false);
108
109 // Music mode
110 xpos = 2; ypos += myLineHeight + 12;
111 lwidth = _font.getStringWidth("Music mode (DF5/DF6/DF7) ");
112 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
113 myFontHeight, "Music mode (DF5/DF6/DF7) ", TextAlign::Left);
114 xpos += lwidth;
115
116 myMusicMode = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 2, 8, Common::Base::F_16);
117 myMusicMode->setTarget(this);
118 myMusicMode->setEditable(false);
119
120 // Current random number
121 xpos = 10; ypos += myLineHeight + 4;
122 new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
123 myFontHeight, "Current random number ", TextAlign::Left);
124 xpos += lwidth;
125
126 myRandom = new DataGridWidget(boss, _nfont, xpos, ypos-2, 1, 1, 2, 8, Common::Base::F_16);
127 myRandom->setTarget(this);
128 myRandom->setEditable(false);
129}
130
131// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
132void CartridgeDPCWidget::saveOldState()
133{
134 myOldState.tops.clear();
135 myOldState.bottoms.clear();
136 myOldState.counters.clear();
137 myOldState.flags.clear();
138 myOldState.music.clear();
139
140 for(uInt32 i = 0; i < 8; ++i)
141 {
142 myOldState.tops.push_back(myCart.myTops[i]);
143 myOldState.bottoms.push_back(myCart.myBottoms[i]);
144 myOldState.counters.push_back(myCart.myCounters[i]);
145 myOldState.flags.push_back(myCart.myFlags[i]);
146 }
147 for(uInt32 i = 0; i < 3; ++i)
148 myOldState.music.push_back(myCart.myMusicMode[i]);
149
150 myOldState.random = myCart.myRandomNumber;
151
152 for(uInt32 i = 0; i < internalRamSize(); ++i)
153 myOldState.internalram.push_back(myCart.myDisplayImage[i]);
154
155 myOldState.bank = myCart.getBank();
156}
157
158// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
159void CartridgeDPCWidget::loadConfig()
160{
161 myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank);
162
163 // Get registers, using change tracking
164 IntArray alist;
165 IntArray vlist;
166 BoolArray changed;
167
168 alist.clear(); vlist.clear(); changed.clear();
169 for(int i = 0; i < 8; ++i)
170 {
171 alist.push_back(0); vlist.push_back(myCart.myTops[i]);
172 changed.push_back(myCart.myTops[i] != myOldState.tops[i]);
173 }
174 myTops->setList(alist, vlist, changed);
175
176 alist.clear(); vlist.clear(); changed.clear();
177 for(int i = 0; i < 8; ++i)
178 {
179 alist.push_back(0); vlist.push_back(myCart.myBottoms[i]);
180 changed.push_back(myCart.myBottoms[i] != myOldState.bottoms[i]);
181 }
182 myBottoms->setList(alist, vlist, changed);
183
184 alist.clear(); vlist.clear(); changed.clear();
185 for(int i = 0; i < 8; ++i)
186 {
187 alist.push_back(0); vlist.push_back(myCart.myCounters[i]);
188 changed.push_back(myCart.myCounters[i] != myOldState.counters[i]);
189 }
190 myCounters->setList(alist, vlist, changed);
191
192 alist.clear(); vlist.clear(); changed.clear();
193 for(int i = 0; i < 8; ++i)
194 {
195 alist.push_back(0); vlist.push_back(myCart.myFlags[i]);
196 changed.push_back(myCart.myFlags[i] != myOldState.flags[i]);
197 }
198 myFlags->setList(alist, vlist, changed);
199
200 alist.clear(); vlist.clear(); changed.clear();
201 for(int i = 0; i < 3; ++i)
202 {
203 alist.push_back(0); vlist.push_back(myCart.myMusicMode[i]);
204 changed.push_back(myCart.myMusicMode[i] != myOldState.music[i]);
205 }
206 myMusicMode->setList(alist, vlist, changed);
207
208 myRandom->setList(0, myCart.myRandomNumber,
209 myCart.myRandomNumber != myOldState.random);
210
211 CartDebugWidget::loadConfig();
212}
213
214// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
215void CartridgeDPCWidget::handleCommand(CommandSender* sender,
216 int cmd, int data, int id)
217{
218 if(cmd == kBankChanged)
219 {
220 myCart.unlockBank();
221 myCart.bank(myBank->getSelected());
222 myCart.lockBank();
223 invalidate();
224 }
225}
226
227// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
228string CartridgeDPCWidget::bankState()
229{
230 ostringstream& buf = buffer();
231
232 static const char* const spot[] = { "$FFF8", "$FFF9" };
233 buf << "Bank = " << std::dec << myCart.getBank()
234 << ", hotspot = " << spot[myCart.getBank()];
235
236 return buf.str();
237}
238
239// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
240uInt32 CartridgeDPCWidget::internalRamSize()
241{
242 return 2*1024;
243}
244
245// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
246uInt32 CartridgeDPCWidget::internalRamRPort(int start)
247{
248 return 0x0000 + start;
249}
250
251// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
252string CartridgeDPCWidget::internalRamDescription()
253{
254 ostringstream desc;
255 desc << "$0000 - $07FF - 2K display data\n"
256 << " indirectly accessible to 6507\n"
257 << " via DPC+'s Data Fetcher\n"
258 << " registers\n";
259
260 return desc.str();
261}
262
263// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
264const ByteArray& CartridgeDPCWidget::internalRamOld(int start, int count)
265{
266 myRamOld.clear();
267 for(int i = 0; i < count; i++)
268 myRamOld.push_back(myOldState.internalram[start + i]);
269 return myRamOld;
270}
271
272// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
273const ByteArray& CartridgeDPCWidget::internalRamCurrent(int start, int count)
274{
275 myRamCurrent.clear();
276 for(int i = 0; i < count; i++)
277 myRamCurrent.push_back(myCart.myDisplayImage[start + i]);
278 return myRamCurrent;
279}
280
281// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
282void CartridgeDPCWidget::internalRamSetValue(int addr, uInt8 value)
283{
284 myCart.myDisplayImage[addr] = value;
285}
286
287// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
288uInt8 CartridgeDPCWidget::internalRamGetValue(int addr)
289{
290 return myCart.myDisplayImage[addr];
291}
292