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