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 "CartDASH.hxx" |
19 | #include "EditTextWidget.hxx" |
20 | #include "PopUpWidget.hxx" |
21 | #include "CartDASHWidget.hxx" |
22 | |
23 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
24 | CartridgeDASHWidget::CartridgeDASHWidget( |
25 | GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, |
26 | int x, int y, int w, int h, CartridgeDASH& 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 << "DASH cartridge - (64K ROM + RAM)\n" |
34 | << " 4-64K ROM (1K banks), 32K RAM (512b banks)\n" |
35 | << "Each 1K ROM selected by writing to $3F\n" |
36 | "Each 512b RAM selected by writing to $3E\n" |
37 | " First 512B of bank x (R)\n" |
38 | " First 512B of bank x+4 (+$800) (W)\n" |
39 | << "Startup bank = 0/-1/-1/0 (ROM)\n" ; |
40 | |
41 | // Eventually, we should query this from the debugger/disassembler |
42 | uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; |
43 | start -= start % 0x1000; |
44 | info << "Bank RORG" << " = $" << Common::Base::HEX4 << start << "\n" ; |
45 | |
46 | int xpos = 2, |
47 | ypos = addBaseInformation(size, "A. Davie & T. Jentzsch" , info.str()) + |
48 | myLineHeight; |
49 | |
50 | VariantList bankno; |
51 | for(uInt32 i = 0; i < myCart.ROM_BANK_COUNT; ++i) |
52 | VarList::push_back(bankno, i, i); |
53 | |
54 | VariantList banktype; |
55 | VarList::push_back(banktype, "ROM" , "ROM" ); |
56 | VarList::push_back(banktype, "RAM" , "RAM" ); |
57 | |
58 | for(uInt32 i = 0; i < 4; ++i) |
59 | { |
60 | int xpos_s, ypos_s = ypos; |
61 | |
62 | ostringstream label; |
63 | label << "Set segment " << i << " as: " ; |
64 | |
65 | new StaticTextWidget(boss, _font, xpos, ypos, _font.getStringWidth(label.str()), |
66 | myFontHeight, label.str(), TextAlign::Left); |
67 | ypos += myLineHeight + 8; |
68 | |
69 | xpos += 20; |
70 | myBankNumber[i] = |
71 | new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("Slot " ), |
72 | myLineHeight, bankno, "Slot " , |
73 | 6*_font.getMaxCharWidth()); |
74 | addFocusWidget(myBankNumber[i]); |
75 | |
76 | xpos += myBankNumber[i]->getWidth(); |
77 | myBankType[i] = |
78 | new PopUpWidget(boss, _font, xpos, ypos-2, 5*_font.getMaxCharWidth(), |
79 | myLineHeight, banktype, " of " , _font.getStringWidth(" of " )); |
80 | addFocusWidget(myBankType[i]); |
81 | |
82 | xpos += myBankType[i]->getWidth() + 10; |
83 | |
84 | myBankCommit[i] = new ButtonWidget(boss, _font, xpos, ypos-4, |
85 | _font.getStringWidth(" Commit " ), myButtonHeight, |
86 | "Commit" , bankEnum[i]); |
87 | myBankCommit[i]->setTarget(this); |
88 | addFocusWidget(myBankCommit[i]); |
89 | |
90 | xpos_s = xpos + myBankCommit[i]->getWidth() + 20; |
91 | |
92 | StaticTextWidget* t; |
93 | int addr1 = start + (i*0x400), addr2 = addr1 + 0x1FF; |
94 | |
95 | label.str("" ); |
96 | label << Common::Base::HEX4 << addr1 << "-" << Common::Base::HEX4 << addr2; |
97 | t = new StaticTextWidget(boss, _font, xpos_s, ypos_s+2, |
98 | _font.getStringWidth(label.str()), myFontHeight, label.str(), TextAlign::Left); |
99 | |
100 | int xoffset = xpos_s+t->getWidth() + 10; |
101 | myBankState[2*i] = new EditTextWidget(boss, _font, xoffset, ypos_s, |
102 | w - xoffset - 10, myLineHeight, "" ); |
103 | myBankState[2*i]->setEditable(false, true); |
104 | ypos_s += myLineHeight + 4; |
105 | |
106 | label.str("" ); |
107 | label << Common::Base::HEX4 << (addr2 + 1) << "-" << Common::Base::HEX4 << (addr2 + 1 + 0x1FF); |
108 | new StaticTextWidget(boss, _font, xpos_s, ypos_s+2, |
109 | _font.getStringWidth(label.str()), myFontHeight, label.str(), TextAlign::Left); |
110 | |
111 | myBankState[2*i+1] = new EditTextWidget(boss, _font, xoffset, ypos_s, |
112 | w - xoffset - 10, myLineHeight, "" ); |
113 | myBankState[2*i+1]->setEditable(false, true); |
114 | |
115 | xpos = 10; |
116 | ypos+= 2 * myLineHeight; |
117 | } |
118 | } |
119 | |
120 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
121 | void CartridgeDASHWidget::saveOldState() |
122 | { |
123 | myOldState.internalram.clear(); |
124 | |
125 | for(uInt32 i = 0; i < internalRamSize(); ++i) |
126 | myOldState.internalram.push_back(myCart.myRAM[i]); |
127 | } |
128 | |
129 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
130 | void CartridgeDASHWidget::loadConfig() |
131 | { |
132 | updateUIState(); |
133 | CartDebugWidget::loadConfig(); |
134 | } |
135 | |
136 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
137 | void CartridgeDASHWidget::handleCommand(CommandSender* sender, |
138 | int cmd, int data, int id) |
139 | { |
140 | uInt16 segment = 0; |
141 | switch(cmd) |
142 | { |
143 | case kBank0Changed: |
144 | segment = 0; |
145 | break; |
146 | case kBank1Changed: |
147 | segment = 1; |
148 | break; |
149 | case kBank2Changed: |
150 | segment = 2; |
151 | break; |
152 | case kBank3Changed: |
153 | segment = 3; |
154 | break; |
155 | } |
156 | |
157 | // Ignore bank if either number or type hasn't been selected |
158 | if(myBankNumber[segment]->getSelected() < 0 || |
159 | myBankType[segment]->getSelected() < 0) |
160 | return; |
161 | |
162 | uInt8 bank = (segment << myCart.BANK_BITS) | |
163 | (myBankNumber[segment]->getSelected() & myCart.BIT_BANK_MASK); |
164 | |
165 | myCart.unlockBank(); |
166 | |
167 | if(myBankType[segment]->getSelectedTag() == "ROM" ) |
168 | myCart.bankROM(bank); |
169 | else |
170 | myCart.bankRAM(bank); |
171 | |
172 | myCart.lockBank(); |
173 | invalidate(); |
174 | updateUIState(); |
175 | } |
176 | |
177 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
178 | string CartridgeDASHWidget::bankState() |
179 | { |
180 | ostringstream& buf = buffer(); |
181 | int lastROMBank = -1; |
182 | bool lastSlotRAM = false; |
183 | |
184 | for(int i = 0; i < 8; ++i) |
185 | { |
186 | uInt16 bank = myCart.bankInUse[i]; |
187 | |
188 | if(bank == myCart.BANK_UNDEFINED) // never accessed |
189 | { |
190 | buf << " U!" ; |
191 | } |
192 | else |
193 | { |
194 | int bankno = bank & myCart.BIT_BANK_MASK; |
195 | |
196 | if(bank & myCart.BITMASK_ROMRAM) // was RAM mapped here? |
197 | { |
198 | // RAM will always need a '+' placed somewhere, since it always |
199 | // consists of 512B segments |
200 | bool inFirstSlot = (i % 2 == 0); |
201 | if(!(inFirstSlot || lastSlotRAM)) |
202 | { |
203 | lastSlotRAM = false; |
204 | buf << " +" ; |
205 | } |
206 | |
207 | if(bank & myCart.BITMASK_LOWERUPPER) // upper is write port |
208 | buf << " RAM " << bankno << "W" ; |
209 | else |
210 | buf << " RAM " << bankno << "R" ; |
211 | |
212 | if(inFirstSlot) |
213 | { |
214 | buf << " +" ; |
215 | lastSlotRAM = true; |
216 | } |
217 | } |
218 | else |
219 | { |
220 | // ROM can be contiguous, since 2 512B segments can form a single |
221 | // 1K bank; in this case we only show the info once |
222 | bool highBankSame = (i % 2 == 1) && (bankno == lastROMBank); |
223 | if(!highBankSame) |
224 | { |
225 | buf << " ROM " << bankno; |
226 | lastROMBank = bankno; |
227 | } |
228 | else |
229 | lastROMBank = -1; |
230 | |
231 | lastSlotRAM = false; |
232 | } |
233 | } |
234 | |
235 | if((i+1) % 2 == 0 && i < 7) |
236 | buf << " /" ; |
237 | } |
238 | |
239 | return buf.str(); |
240 | } |
241 | |
242 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
243 | void CartridgeDASHWidget::updateUIState() |
244 | { |
245 | // Set contents for actual banks number and type |
246 | for(int i = 0; i < 4; ++i) |
247 | { |
248 | uInt16 segment = myCart.segmentInUse[i]; |
249 | |
250 | if(segment == myCart.BANK_UNDEFINED) |
251 | { |
252 | myBankNumber[i]->clearSelection(); |
253 | myBankType[i]->clearSelection(); |
254 | } |
255 | else |
256 | { |
257 | int bankno = segment & myCart.BIT_BANK_MASK; |
258 | const string& banktype = (segment & myCart.BITMASK_ROMRAM) ? "RAM" : "ROM" ; |
259 | |
260 | myBankNumber[i]->setSelected(bankno); |
261 | myBankType[i]->setSelected(banktype); |
262 | } |
263 | } |
264 | |
265 | // Set description for each 512b bank state |
266 | for(int i = 0; i < 8; ++i) |
267 | { |
268 | uInt16 bank = myCart.bankInUse[i]; |
269 | |
270 | if(bank == myCart.BANK_UNDEFINED) // never accessed |
271 | { |
272 | myBankState[i]->setText("Undefined" ); |
273 | } |
274 | else |
275 | { |
276 | ostringstream buf; |
277 | int bankno = bank & myCart.BIT_BANK_MASK; |
278 | |
279 | if(bank & myCart.BITMASK_ROMRAM) // was RAM mapped here? |
280 | { |
281 | if(bank & myCart.BITMASK_LOWERUPPER) // upper is write port |
282 | { |
283 | buf << "RAM " << bankno << " @ $" << Common::Base::HEX4 |
284 | << (bankno << myCart.RAM_BANK_TO_POWER) << " (W)" ; |
285 | myBankState[i]->setText(buf.str()); |
286 | } |
287 | else |
288 | { |
289 | buf << "RAM " << bankno << " @ $" << Common::Base::HEX4 |
290 | << (bankno << myCart.RAM_BANK_TO_POWER) << " (R)" ; |
291 | myBankState[i]->setText(buf.str()); |
292 | } |
293 | } |
294 | else |
295 | { |
296 | if(bank & myCart.BITMASK_LOWERUPPER) // upper is high 512b |
297 | { |
298 | buf << "ROM " << bankno << " @ $" << Common::Base::HEX4 |
299 | << ((bankno << myCart.RAM_BANK_TO_POWER) + myCart.RAM_BANK_SIZE); |
300 | myBankState[i]->setText(buf.str()); |
301 | } |
302 | else |
303 | { |
304 | buf << "ROM " << bankno << " @ $" << Common::Base::HEX4 |
305 | << (bankno << myCart.RAM_BANK_TO_POWER); |
306 | myBankState[i]->setText(buf.str()); |
307 | } |
308 | } |
309 | } |
310 | } |
311 | } |
312 | |
313 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
314 | uInt32 CartridgeDASHWidget::internalRamSize() |
315 | { |
316 | return 32*1024; |
317 | } |
318 | |
319 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
320 | uInt32 CartridgeDASHWidget::internalRamRPort(int start) |
321 | { |
322 | return 0x0000 + start; |
323 | } |
324 | |
325 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
326 | string CartridgeDASHWidget::internalRamDescription() |
327 | { |
328 | ostringstream desc; |
329 | desc << "Accessible 512b at a time via:\n" |
330 | << " $F000/$F200/$F400/etc used for Read Access\n" |
331 | << " $F800/$FA00/$FC00/etc used for Write Access (+$800)" ; |
332 | |
333 | return desc.str(); |
334 | } |
335 | |
336 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
337 | const ByteArray& CartridgeDASHWidget::internalRamOld(int start, int count) |
338 | { |
339 | myRamOld.clear(); |
340 | for(int i = 0; i < count; i++) |
341 | myRamOld.push_back(myOldState.internalram[start + i]); |
342 | return myRamOld; |
343 | } |
344 | |
345 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
346 | const ByteArray& CartridgeDASHWidget::internalRamCurrent(int start, int count) |
347 | { |
348 | myRamCurrent.clear(); |
349 | for(int i = 0; i < count; i++) |
350 | myRamCurrent.push_back(myCart.myRAM[start + i]); |
351 | return myRamCurrent; |
352 | } |
353 | |
354 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
355 | void CartridgeDASHWidget::internalRamSetValue(int addr, uInt8 value) |
356 | { |
357 | myCart.myRAM[addr] = value; |
358 | } |
359 | |
360 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
361 | uInt8 CartridgeDASHWidget::internalRamGetValue(int addr) |
362 | { |
363 | return myCart.myRAM[addr]; |
364 | } |
365 | |
366 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
367 | const CartridgeDASHWidget::BankID CartridgeDASHWidget::bankEnum[4] = { |
368 | kBank0Changed, kBank1Changed, kBank2Changed, kBank3Changed |
369 | }; |
370 | |