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