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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
24Cartridge3EPlusWidget::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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
123void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
132void Cartridge3EPlusWidget::loadConfig()
133{
134 updateUIState();
135 CartDebugWidget::loadConfig();
136}
137
138// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
139void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
180string 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
211void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
280uInt32 Cartridge3EPlusWidget::internalRamSize()
281{
282 return 32*1024;
283}
284
285// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
286uInt32 Cartridge3EPlusWidget::internalRamRPort(int start)
287{
288 return 0x0000 + start;
289}
290
291// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
292string 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
303const 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
312const 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
321void Cartridge3EPlusWidget::internalRamSetValue(int addr, uInt8 value)
322{
323 myCart.myRAM[addr] = value;
324}
325
326// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
327uInt8 Cartridge3EPlusWidget::internalRamGetValue(int addr)
328{
329 return myCart.myRAM[addr];
330}
331
332// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
333const Cartridge3EPlusWidget::BankID Cartridge3EPlusWidget::bankEnum[4] = {
334 kBank0Changed, kBank1Changed, kBank2Changed, kBank3Changed
335};
336