| 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 | |