diff --git a/.gitignore b/.gitignore index 8e6d3e86a..e1dce7f74 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ build/ src/macosx/M6502.ins *.dSYM .vscode/c_cpp_properties.json +.vscode/settings.json src/windows/sdl/* src/windows/x64/* src/windows/Win32/* diff --git a/src/debugger/gui/CartCDFInfoWidget.cxx b/src/debugger/gui/CartCDFInfoWidget.cxx index b56c61ca1..a1db55cdf 100644 --- a/src/debugger/gui/CartCDFInfoWidget.cxx +++ b/src/debugger/gui/CartCDFInfoWidget.cxx @@ -23,16 +23,16 @@ CartridgeCDFInfoWidget::CartridgeCDFInfoWidget( int x, int y, int w, int h, CartridgeCDF& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h) { - uInt16 size = 8 * 4096; - ostringstream info; - info << describeCDFVersion(cart.myCDFSubtype) << " cartridge\n" - << "32K ROM, seven 4K banks are accessible to 2600\n" - << "8K CDF RAM\n" - << "CDF registers accessible @ $FFF0 - $FFF3\n" - << "Banks accessible at hotspots $FFF5 to $FFFB\n" - << "Startup bank = " << cart.startBank() << "\n"; + info << describeCDFVersion(cart.myCDFSubtype) << " cartridge\n" + << (cart.romSize() / 1024) << "K ROM\n" + << (cart.ramSize() / 1024) << "K RAM\n" + << "Seven 4K banks are available to 2600\n" + << "Functions accessible @ $FFF0 - $FFF3\n" + << (cart.isCDFJplus() ? "Banks accessible @ $FFF4 to $FFFA\n" : "Banks accessible @ $FFF5 to $FFFB\n") + << "Startup bank = " << cart.startBank() << "\n"; + #if 0 // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF5; i < 7; ++i, offset += 0x1000) @@ -44,7 +44,7 @@ CartridgeCDFInfoWidget::CartridgeCDFInfoWidget( } #endif - addBaseInformation(size, "AtariAge", info.str()); + addBaseInformation(cart.romSize(), "AtariAge", info.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -61,6 +61,9 @@ string CartridgeCDFInfoWidget::describeCDFVersion(CartridgeCDF::CDFSubtype subty case CartridgeCDF::CDFSubtype::CDFJ: return "CDFJ"; + case CartridgeCDF::CDFSubtype::CDFJplus: + return "CDFJ+"; + default: throw runtime_error("unreachable"); } diff --git a/src/debugger/gui/CartCDFWidget.cxx b/src/debugger/gui/CartCDFWidget.cxx index 8c4fdf2fc..23027495e 100644 --- a/src/debugger/gui/CartCDFWidget.cxx +++ b/src/debugger/gui/CartCDFWidget.cxx @@ -34,13 +34,23 @@ CartridgeCDFWidget::CartridgeCDFWidget( int xpos = HBORDER, ypos = VBORDER; VariantList items; - VarList::push_back(items, "0 ($FFF5)"); - VarList::push_back(items, "1 ($FFF6)"); - VarList::push_back(items, "2 ($FFF7)"); - VarList::push_back(items, "3 ($FFF8)"); - VarList::push_back(items, "4 ($FFF9)"); - VarList::push_back(items, "5 ($FFFA)"); - VarList::push_back(items, "6 ($FFFB)"); + if (isCDFJplus()) { + VarList::push_back(items, "0 ($FFF4)"); + VarList::push_back(items, "1 ($FFF5)"); + VarList::push_back(items, "2 ($FFF6)"); + VarList::push_back(items, "3 ($FFF7)"); + VarList::push_back(items, "4 ($FFF8)"); + VarList::push_back(items, "5 ($FFF9)"); + VarList::push_back(items, "6 ($FFFA)"); + } else { + VarList::push_back(items, "0 ($FFF5)"); + VarList::push_back(items, "1 ($FFF6)"); + VarList::push_back(items, "2 ($FFF7)"); + VarList::push_back(items, "3 ($FFF8)"); + VarList::push_back(items, "4 ($FFF9)"); + VarList::push_back(items, "5 ($FFFA)"); + VarList::push_back(items, "6 ($FFFB)"); + } myBank = new PopUpWidget(boss, _font, xpos, ypos, _font.getStringWidth("0 ($FFFx)"), myLineHeight, items, "Set bank ", 0, kBankChanged); @@ -73,7 +83,7 @@ CartridgeCDFWidget::CartridgeCDFWidget( myCommandStreamPointer->setTarget(this); myCommandStreamPointer->setEditable(false); - if (isCDFJ()) + if (isCDFJ() || isCDFJplus()) myJumpStreamPointers = new DataGridWidget(boss, _nfont, DS_X + myDatastreamPointers->getWidth() * 2 / 4, ypos+myLineHeight + 9*myLineHeight, 2, 1, 6, 32, Common::Base::Fmt::_16_3_2); @@ -102,7 +112,7 @@ CartridgeCDFWidget::CartridgeCDFWidget( new StaticTextWidget(_boss, _font, DS_X - _font.getStringWidth("xx "), ypos+myLineHeight + 9*myLineHeight + 2, lwidth, myFontHeight, - isCDFJ() ? "Jump Data (21|22)" : "Jump Data (21)"); + (isCDFJ() || isCDFJplus()) ? "Jump Data (21|22)" : "Jump Data (21)"); // Datastream Increments xpos = DS_X + myDatastreamPointers->getWidth() + 16; @@ -121,7 +131,7 @@ CartridgeCDFWidget::CartridgeCDFWidget( myCommandStreamIncrement->setEditable(false); myJumpStreamIncrements = new DataGridWidget(boss, _nfont, xpos, - ypos+myLineHeight + 9*myLineHeight, isCDFJ() ? 2 : 1, 1, 5, 32, + ypos+myLineHeight + 9*myLineHeight, (isCDFJ() || isCDFJplus()) ? 2 : 1, 1, 5, 32, Common::Base::Fmt::_16_2_2); myJumpStreamIncrements->setTarget(this); myJumpStreamIncrements->setEditable(false); @@ -205,7 +215,7 @@ void CartridgeCDFWidget::saveOldState() myOldState.internalram.clear(); myOldState.samplepointer.clear(); - for(uInt32 i = 0; i < static_cast(isCDFJ() ? 35 : 34); ++i) + for(uInt32 i = 0; i < static_cast((isCDFJ() || isCDFJplus()) ? 35 : 34); ++i) { // Pointers are stored as: // PPPFF--- @@ -281,7 +291,7 @@ void CartridgeCDFWidget::loadConfig() myCommandStreamPointer->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); - for(int i = 0; i < (isCDFJ() ? 2 : 1); ++i) + for(int i = 0; i < ((isCDFJ() || isCDFJplus()) ? 2 : 1); ++i) { Int32 pointervalue = myCart.getDatastreamPointer(0x21 + i) >> 12; alist.push_back(0); vlist.push_back(pointervalue); @@ -305,7 +315,7 @@ void CartridgeCDFWidget::loadConfig() myCommandStreamIncrement->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); - for(int i = 0; i < (isCDFJ() ? 2 : 1); ++i) + for(int i = 0; i < ((isCDFJ() || isCDFJplus()) ? 2 : 1); ++i) { Int32 pointervalue = myCart.getDatastreamIncrement(0x21 + i) >> 12; alist.push_back(0); vlist.push_back(pointervalue); @@ -387,11 +397,12 @@ string CartridgeCDFWidget::bankState() { ostringstream& buf = buffer(); - static constexpr std::array spot = { - "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB" + static constexpr std::array spot = { + "$FFF4", "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB" }; + buf << "Bank = " << std::dec << myCart.getBank() - << ", hotspot = " << spot[myCart.getBank()]; + << ", hotspot = " << spot[myCart.getBank() + (isCDFJplus() ? 0 : 1)]; return buf.str(); } @@ -399,7 +410,7 @@ string CartridgeCDFWidget::bankState() // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCDFWidget::internalRamSize() { - return 8*1024; + return myCart.ramSize(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -412,13 +423,21 @@ uInt32 CartridgeCDFWidget::internalRamRPort(int start) string CartridgeCDFWidget::internalRamDescription() { ostringstream desc; - desc << "$0000 - $07FF - CDF driver\n" - << " not accessible to 6507\n" - << "$0800 - $17FF - 4K Data Stream storage\n" - << " indirectly accessible to 6507\n" - << " via CDF's Data Stream registers\n" - << "$1800 - $1FFF - 2K C variable storage and stack\n" - << " not accessible to 6507"; + if (isCDFJplus()) { + desc << "$0000 - $07FF - CDFJ+ driver\n" + << " not accessible to 6507\n" + << "$0800 - $7FFF - 30K Data Stream storage\n" + << " indirectly accessible to 6507\n" + << " via fast fecthers\n"; + } else { + desc << "$0000 - $07FF - CDF/CDFJ driver\n" + << " not accessible to 6507\n" + << "$0800 - $17FF - 4K Data Stream storage\n" + << " indirectly accessible to 6507\n" + << " via fast fetchers\n" + << "$1800 - $1FFF - 2K C variable storage and stack\n" + << " not accessible to 6507"; + } return desc.str(); } @@ -467,6 +486,9 @@ string CartridgeCDFWidget::describeCDFVersion(CartridgeCDF::CDFSubtype subtype) case CartridgeCDF::CDFSubtype::CDFJ: return "CDFJ"; + case CartridgeCDF::CDFSubtype::CDFJplus: + return "CDFJ+"; + default: throw runtime_error("unreachable"); } @@ -475,5 +497,10 @@ string CartridgeCDFWidget::describeCDFVersion(CartridgeCDF::CDFSubtype subtype) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCDFWidget::isCDFJ() const { - return myCart.myCDFSubtype == CartridgeCDF::CDFSubtype::CDFJ; + return (myCart.myCDFSubtype == CartridgeCDF::CDFSubtype::CDFJ); } + +bool CartridgeCDFWidget::isCDFJplus() const +{ + return (myCart.isCDFJplus()); +} \ No newline at end of file diff --git a/src/debugger/gui/CartCDFWidget.hxx b/src/debugger/gui/CartCDFWidget.hxx index fdf5622a9..431553db6 100644 --- a/src/debugger/gui/CartCDFWidget.hxx +++ b/src/debugger/gui/CartCDFWidget.hxx @@ -75,6 +75,7 @@ class CartridgeCDFWidget : public CartDebugWidget private: bool isCDFJ() const; + bool isCDFJplus() const; static string describeCDFVersion(CartridgeCDF::CDFSubtype subtype); diff --git a/src/emucore/CartBUS.cxx b/src/emucore/CartBUS.cxx index 46d220bbf..edd56d72c 100644 --- a/src/emucore/CartBUS.cxx +++ b/src/emucore/CartBUS.cxx @@ -68,8 +68,12 @@ CartridgeBUS::CartridgeBUS(const ByteBuffer& image, size_t size, reinterpret_cast(myImage.get()), reinterpret_cast(myRAM.data()), static_cast(32_KB), - devSettings ? settings.getBool("dev.thumb.trapfatal") : false, Thumbulator::ConfigureFor::BUS, this - ); + 0x00000800, + 0x00000808, + 0x40001FDC, + devSettings ? settings.getBool("dev.thumb.trapfatal") : false, + Thumbulator::ConfigureFor::BUS, + this); setInitialState(); } diff --git a/src/emucore/CartCDF.cxx b/src/emucore/CartCDF.cxx index e09480464..1155c307a 100644 --- a/src/emucore/CartCDF.cxx +++ b/src/emucore/CartCDF.cxx @@ -29,14 +29,17 @@ #include "TIA.hxx" #include "exception/FatalEmulationError.hxx" -#define DSRAM 0x0800 - #define COMMSTREAM 0x20 #define JUMPSTREAM_BASE 0x21 #define FAST_FETCH_ON ((myMode & 0x0F) == 0) #define DIGITAL_AUDIO_ON ((myMode & 0xF0) == 0) +#define getUInt32(_array, _address) ((_array)[(_address) + 0] + \ + ((_array)[(_address) + 1] << 8) + \ + ((_array)[(_address) + 2] << 16) + \ + ((_array)[(_address) + 3] << 24)) + namespace { Thumbulator::ConfigureFor thumulatorConfiguration(CartridgeCDF::CDFSubtype subtype) { @@ -50,6 +53,9 @@ namespace { case CartridgeCDF::CDFSubtype::CDFJ: return Thumbulator::ConfigureFor::CDFJ; + case CartridgeCDF::CDFSubtype::CDFJplus: + return Thumbulator::ConfigureFor::CDFJplus; + default: throw runtime_error("unreachable"); } @@ -60,34 +66,50 @@ namespace { CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size, const string& md5, const Settings& settings) : Cartridge(settings, md5), - myImage(make_unique(32_KB)) + myImage(make_unique(512_KB)) { // Copy the ROM image into my buffer - std::fill_n(myImage.get(), 32_KB, 0); - std::copy_n(image.get(), std::min(32_KB, size), myImage.get()); + std::fill_n(myImage.get(), 512_KB, 0); + std::copy_n(image.get(), std::min(512_KB, size), myImage.get()); - // even though the ROM is 32K, only 28K is accessible to the 6507 - createRomAccessArrays(28_KB); + // Detect cart version + setupVersion(); - // Pointer to the program ROM (28K @ 0 byte offset) - // which starts after the 2K CDF Driver and 2K C Code - myProgramImage = myImage.get() + 4_KB; + // The lowest 2K is not accessible to the debugger + createRomAccessArrays(isCDFJplus() ? 510_KB : 28_KB); + + // Pointer to the program ROM + // which starts after the 2K driver (and 2K C Code for CDF) + myProgramImage = myImage.get() + (isCDFJplus() ? 2_KB : 4_KB); // Pointer to CDF driver in RAM myDriverImage = myRAM.data(); - // Pointer to the display RAM - myDisplayImage = myRAM.data() + DSRAM; + // Pointer to the display RAM (starts after 2K driver) + myDisplayImage = myRAM.data() + 2_KB; - setupVersion(); + // C addresses + uInt32 cBase, cStart, cStack; + if (isCDFJplus()) { + cBase = getUInt32(myImage.get(), 0x17F8) & 0xFFFFFFFE; // C Base Address + cStart = cBase; // C Start Address + cStack = getUInt32(myImage.get(), 0x17F4); // C Stack + } else { + cBase = 0x800; // C Base Address + cStart = 0x808; // C Start Address (skip ARM header) + cStack = 0x40001FDC; // C Stack + } // Create Thumbulator ARM emulator bool devSettings = settings.getBool("dev.settings"); myThumbEmulator = make_unique( reinterpret_cast(myImage.get()), reinterpret_cast(myRAM.data()), - static_cast(32_KB), - devSettings ? settings.getBool("dev.thumb.trapfatal") : false, thumulatorConfiguration(myCDFSubtype), this); + static_cast(512_KB), + cBase, cStart, cStack, + devSettings ? settings.getBool("dev.thumb.trapfatal") : false, + thumulatorConfiguration(myCDFSubtype), + this); setInitialState(); } @@ -97,8 +119,8 @@ void CartridgeCDF::reset() { initializeRAM(myRAM.data()+2_KB, myRAM.size()-2_KB); - // CDF always starts in bank 6 - initializeStartBank(6); + // CDF always starts in bank 6, CDFJ+ in bank 0 + initializeStartBank(isCDFJplus() ? 0 : 6); myAudioCycles = myARMCycles = 0; myFractionalClocks = 0.0; @@ -123,7 +145,6 @@ void CartridgeCDF::setInitialState() myBankOffset = myLDAimmediateOperandAddress = myJMPoperandAddress = 0; myFastJumpActive = myFastJumpStream = 0; - } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -195,7 +216,6 @@ inline void CartridgeCDF::callFunction(uInt8 value) uInt8 CartridgeCDF::peek(uInt16 address) { address &= 0x0FFF; - uInt8 peekvalue = myProgramImage[myBankOffset + address]; // In debugger/bank-locked mode, we ignore all hotspots and in general @@ -214,8 +234,14 @@ uInt8 CartridgeCDF::peek(uInt16 address) ++myJMPoperandAddress; pointer = getDatastreamPointer(myFastJumpStream); - value = myDisplayImage[ pointer >> 20 ]; - pointer += 0x100000; // always increment by 1 + if (isCDFJplus()) { + value = myDisplayImage[ pointer >> 16 ]; + pointer += 0x00010000; // always increment by 1 + } else { + value = myDisplayImage[ pointer >> 20 ]; + pointer += 0x00100000; // always increment by 1 + } + setDatastreamPointer(myFastJumpStream, pointer); return value; @@ -254,9 +280,9 @@ uInt8 CartridgeCDF::peek(uInt16 address) uInt32 sampleaddress = getSample() + (myMusicCounters[0] >> 21); // get sample value from ROM or RAM - if (sampleaddress < 0x8000) + if (sampleaddress < 0x00080000) peekvalue = myImage[sampleaddress]; - else if (sampleaddress >= 0x40000000 && sampleaddress < 0x40002000) // check for RAM + else if (sampleaddress >= 0x40000000 && sampleaddress < 0x40008000) // check for RAM peekvalue = myRAM[sampleaddress - 0x40000000]; else peekvalue = 0; @@ -284,39 +310,36 @@ uInt8 CartridgeCDF::peek(uInt16 address) // Switch banks if necessary switch(address) { - case 0xFF5: - // Set the current bank to the first 4k bank - bank(0); + case 0x0FF4: + bank(isCDFJplus() ? 0 : 6); + break; + + case 0x0FF5: + bank(isCDFJplus() ? 1 : 0); break; case 0x0FF6: - // Set the current bank to the second 4k bank - bank(1); + bank(isCDFJplus() ? 2 : 1); break; case 0x0FF7: - // Set the current bank to the third 4k bank - bank(2); + bank(isCDFJplus() ? 3 : 2); break; case 0x0FF8: - // Set the current bank to the fourth 4k bank - bank(3); + bank(isCDFJplus() ? 4 : 3); break; case 0x0FF9: - // Set the current bank to the fifth 4k bank - bank(4); + bank(isCDFJplus() ? 5 : 4); break; case 0x0FFA: - // Set the current bank to the sixth 4k bank - bank(5); + bank(isCDFJplus() ? 6 : 5); break; case 0x0FFB: - // Set the current bank to the last 4k bank - bank(6); + bank(isCDFJplus() ? 0 : 6); break; default: @@ -335,65 +358,71 @@ bool CartridgeCDF::poke(uInt16 address, uInt8 value) uInt32 pointer; address &= 0x0FFF; - switch(address) { - case 0xFF0: // DSWRITE + case 0x0FF0: // DSWRITE pointer = getDatastreamPointer(COMMSTREAM); - myDisplayImage[ pointer >> 20 ] = value; - pointer += 0x100000; // always increment by 1 when writing + if (isCDFJplus()) { + myDisplayImage[ pointer >> 16 ] = value; + pointer += 0x00010000; // always increment by 1 when writing + } else { + myDisplayImage[ pointer >> 20 ] = value; + pointer += 0x00100000; // always increment by 1 when writing + } setDatastreamPointer(COMMSTREAM, pointer); break; - case 0xFF1: // DSPTR + case 0x0FF1: // DSPTR pointer = getDatastreamPointer(COMMSTREAM); - pointer <<=8; - pointer &= 0xf0000000; - pointer |= (value << 20); + pointer <<= 8; + if (isCDFJplus()) { + pointer &= 0xff000000; + pointer |= (value << 16); + } else { + pointer &= 0xf0000000; + pointer |= (value << 20); + } setDatastreamPointer(COMMSTREAM, pointer); break; - case 0xFF2: // SETMODE + case 0x0FF2: // SETMODE myMode = value; break; - case 0xFF3: // CALLFN + case 0x0FF3: // CALLFN callFunction(value); break; - case 0xFF5: - // Set the current bank to the first 4k bank - bank(0); + case 0x00FF4: + bank(isCDFJplus() ? 0 : 6); + break; + + case 0x0FF5: + bank(isCDFJplus() ? 1 : 0); break; case 0x0FF6: - // Set the current bank to the second 4k bank - bank(1); + bank(isCDFJplus() ? 2 : 1); break; case 0x0FF7: - // Set the current bank to the third 4k bank - bank(2); + bank(isCDFJplus() ? 3 : 2); break; case 0x0FF8: - // Set the current bank to the fourth 4k bank - bank(3); + bank(isCDFJplus() ? 4 : 3); break; case 0x0FF9: - // Set the current bank to the fifth 4k bank - bank(4); + bank(isCDFJplus() ? 5 : 4); break; case 0x0FFA: - // Set the current bank to the sixth 4k bank - bank(5); + bank(isCDFJplus() ? 6 : 5); break; case 0x0FFB: - // Set the current bank to the last 4k bank - bank(6); + bank(isCDFJplus() ? 0 : 6); break; default: @@ -419,7 +448,7 @@ bool CartridgeCDF::bank(uInt16 bank, uInt16) { access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romPeekCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF)]; - access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + 28_KB]; + access.romPokeCounter = &myRomAccessCounter[myBankOffset + (addr & 0x0FFF) + 28_KB]; // TODO: Change for CDFJ+??? mySystem->setPageAccess(addr, access); } return myBankChanged = true; @@ -455,7 +484,7 @@ bool CartridgeCDF::patch(uInt16 address, uInt8 value) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteBuffer& CartridgeCDF::getImage(size_t& size) const { - size = 32_KB; + size = 512_KB; return myImage; } @@ -617,11 +646,13 @@ uInt32 CartridgeCDF::getWaveform(uInt8 index) const (myRAM[address + 2] << 16) + (myRAM[address + 3] << 24); // high byte - result -= (0x40000000 + DSRAM); - - if (result >= 4096) - result &= 4095; + result -= (0x40000000 + 2_KB); + if (!isCDFJplus()) { + if (result >= 4096) { + result &= 4095; + } + } return result; } @@ -659,8 +690,16 @@ uInt8 CartridgeCDF::readFromDatastream(uInt8 index) uInt32 pointer = getDatastreamPointer(index); uInt16 increment = getDatastreamIncrement(index); - uInt8 value = myDisplayImage[ pointer >> 20 ]; - pointer += (increment << 12); + + uInt8 value; + if (isCDFJplus()) { + value = myDisplayImage[ pointer >> 16 ]; + pointer += (increment << 8); + } else { + value = myDisplayImage[ pointer >> 20 ]; + pointer += (increment << 12); + } + setDatastreamPointer(index, pointer); return value; } @@ -668,8 +707,21 @@ uInt8 CartridgeCDF::readFromDatastream(uInt8 index) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCDF::setupVersion() { - uInt8 subversion = 0; + // CDFJ+ detection + if (getUInt32(myImage.get(), 0x174) == 0x53554c50 && // Plus + getUInt32(myImage.get(), 0x178) == 0x4a464443 && // CDFJ + getUInt32(myImage.get(), 0x17C) == 0x00000001) { // V1 + myCDFSubtype = CDFSubtype::CDFJplus; + myAmplitudeStream = 0x23; + myFastjumpStreamIndexMask = 0xfe; + myDatastreamBase = 0x0098; + myDatastreamIncrementBase = 0x0124; + myWaveformBase = 0x01b0; + return; + } + + uInt8 subversion = 0; for(uInt32 i = 0; i < 2048; i += 4) { // CDF signature occurs 3 times in a row, i+3 (+7 or +11) is version @@ -683,6 +735,7 @@ void CartridgeCDF::setupVersion() } switch (subversion) { + case 0x4a: myCDFSubtype = CDFSubtype::CDFJ; @@ -727,11 +780,29 @@ string CartridgeCDF::name() const return "CartridgeCDF1"; case CDFSubtype::CDFJ: return "CartridgeCDFJ"; + case CDFSubtype::CDFJplus: + return "CartridgeCDFJ+"; default: return "Cart unknown"; } } +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeCDF::isCDFJplus() const +{ + return (myCDFSubtype == CDFSubtype::CDFJplus); +} + +uInt32 CartridgeCDF::ramSize() const +{ + return isCDFJplus() ? 32_KB : 8_KB; +} + +uInt32 CartridgeCDF::romSize() const +{ + return isCDFJplus() ? 512_KB : 32_KB; +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #ifdef DEBUGGER_SUPPORT CartDebugWidget* CartridgeCDF::debugWidget(GuiObject* boss, const GUI::Font& lfont, diff --git a/src/emucore/CartCDF.hxx b/src/emucore/CartCDF.hxx index cf172b8d2..fd374d9df 100644 --- a/src/emucore/CartCDF.hxx +++ b/src/emucore/CartCDF.hxx @@ -25,16 +25,15 @@ class Thumbulator; #include "Cart.hxx" /** - Cartridge class used for CDF. + Cartridge class used for CDF/CDFJ/CDFJ+. There are seven 4K program banks, a 4K Display Data RAM, 1K C Variable and Stack, and the CDF chip. CDF chip access is mapped to $1000 - $103F (both read and write). - Program banks are accessible by read/write to $1FF5 - $1FFB. - + Program banks are accessible by read/write to $1FF5 - $1FFB FIXME: THIS NEEDS TO BE UPDATED - @authors: Darrell Spice Jr, Chris Walton, Fred Quimby, + @authors: Darrell Spice Jr, Chris Walton, Fred Quimby, John Champeau Stephen Anthony, Bradford W. Mott */ class CartridgeCDF : public Cartridge @@ -48,7 +47,8 @@ class CartridgeCDF : public Cartridge enum class CDFSubtype { CDF0, CDF1, - CDFJ + CDFJ, + CDFJplus }; public: @@ -154,6 +154,21 @@ class CartridgeCDF : public Cartridge */ uInt32 thumbCallback(uInt8 function, uInt32 value1, uInt32 value2) override; + /** + Set if we are using CDFJ+ bankswitching + */ + bool isCDFJplus() const; + + /** + Size of SRAM (RAM) area in cart + */ + uInt32 ramSize() const; + + /** + Size of Flash memory (ROM) area in cart + */ + uInt32 romSize() const; + #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings @@ -220,23 +235,26 @@ class CartridgeCDF : public Cartridge void setupVersion(); private: - // The 32K ROM image of the cartridge + // The ROM image of the cartridge ByteBuffer myImage; - // Pointer to the 28K program ROM image of the cartridge + // Pointer to the program ROM image of the cartridge uInt8* myProgramImage{nullptr}; - // Pointer to the 4K display ROM image of the cartridge + // Pointer to the display ROM image of the cartridge uInt8* myDisplayImage{nullptr}; - // Pointer to the 2K CDF driver image in RAM + // Pointer to the driver image in RAM uInt8* myDriverImage{nullptr}; - // The CDF 8k RAM image, used as: - // $0000 - 2K CDF driver + // The CDFJ 8K RAM image, used as: + // $0000 - 2K Driver // $0800 - 4K Display Data // $1800 - 2K C Variable & Stack - std::array myRAM; + // For CDFJ+, used as: + // $0000 - 2K Driver + // $0800 - Display Data, C Variables & Stack + std::array myRAM; // Pointer to the Thumb ARM emulator object unique_ptr myThumbEmulator; diff --git a/src/emucore/CartDPCPlus.cxx b/src/emucore/CartDPCPlus.cxx index 71500ee94..17494b8cb 100644 --- a/src/emucore/CartDPCPlus.cxx +++ b/src/emucore/CartDPCPlus.cxx @@ -54,6 +54,9 @@ CartridgeDPCPlus::CartridgeDPCPlus(const ByteBuffer& image, size_t size, (reinterpret_cast(myImage.get()), reinterpret_cast(myDPCRAM.data()), static_cast(32_KB), + 0x00000C00, + 0x00000C08, + 0x40001FDC, devSettings ? settings.getBool("dev.thumb.trapfatal") : false, Thumbulator::ConfigureFor::DPCplus, this); diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx index dba8bb3e4..6874c2576 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -169,6 +169,8 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si type = Bankswitch::Type::_3E; else if(isProbably3F(image, size)) type = Bankswitch::Type::_3F; + else if (isProbablyCDF(image, size)) + type = Bankswitch::Type::_CDF; else if(isProbably4A50(image, size)) type = Bankswitch::Type::_4A50; else if(isProbablyEF(image, size, type)) @@ -188,6 +190,8 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si ; // type has been set directly in the function else if(isProbably3F(image, size)) type = Bankswitch::Type::_3F; + else if (isProbablyCDF(image, size)) + type = Bankswitch::Type::_CDF; else if(isProbably4A50(image, size)) type = Bankswitch::Type::_4A50; else /*if(isProbablySB(image, size))*/ @@ -203,6 +207,8 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si ; // type has been set directly in the function else if(isProbably3F(image, size)) type = Bankswitch::Type::_3F; + else if (isProbablyCDF(image, size)) + type = Bankswitch::Type::_CDF; else /*if(isProbablySB(image, size))*/ type = Bankswitch::Type::_SB; } @@ -216,6 +222,8 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si type = Bankswitch::Type::_3E; else if(isProbably3F(image, size)) type = Bankswitch::Type::_3F; + else if (isProbablyCDF(image, size)) + type = Bankswitch::Type::_CDF; } else // what else can we do? { @@ -444,7 +452,9 @@ bool CartDetector::isProbablyCDF(const ByteBuffer& image, size_t size) // Note: all Harmony/Melody custom drivers also contain the value // 0x10adab1e (LOADABLE) if needed for future improvement uInt8 cdf[] = { 'C', 'D', 'F' }; - return searchForBytes(image, size, cdf, 3, 3); + uInt8 cdfjplus[] = { 'P', 'L', 'U', 'S', 'C', 'D', 'F', 'J' }; + return (searchForBytes(image, size, cdf, 3, 3) || + searchForBytes(image, size, cdfjplus, 8, 1)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Thumbulator.cxx b/src/emucore/Thumbulator.cxx index 2984159cd..a9d5f3435 100644 --- a/src/emucore/Thumbulator.cxx +++ b/src/emucore/Thumbulator.cxx @@ -54,10 +54,14 @@ using Common::Base; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Thumbulator::Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, uInt16 rom_size, + const uInt32 c_base, const uInt32 c_start, const uInt32 c_stack, bool traponfatal, Thumbulator::ConfigureFor configurefor, Cartridge* cartridge) : rom(rom_ptr), romSize(rom_size), + cBase(c_base), + cStart(c_start), + cStack(c_stack), decodedRom(make_unique(romSize / 2)), // NOLINT ram(ram_ptr), configuration(configurefor), @@ -217,7 +221,7 @@ uInt32 Thumbulator::fetch16(uInt32 addr) void Thumbulator::write16(uInt32 addr, uInt32 data) { #ifndef UNSAFE_OPTIMIZATIONS - if((addr > 0x40001fff) && (addr < 0x50000000)) + if((addr > 0x40007fff) && (addr < 0x50000000)) fatalError("write16", addr, "abort - out of range"); if (isProtected(addr)) fatalError("write16", addr, "to driver area"); @@ -376,6 +380,7 @@ bool Thumbulator::isProtected(uInt32 addr) return (addr < 0x0800) && (addr > 0x0028) && !((addr >= 0x00a0) && (addr < (0x00a0 + 284))); case ConfigureFor::CDFJ: + case ConfigureFor::CDFJplus: return (addr < 0x0800) && (addr > 0x0028) && !((addr >= 0x0098) && (addr < (0x0098 + 292))); case ConfigureFor::BUS: @@ -391,9 +396,9 @@ uInt32 Thumbulator::read16(uInt32 addr) { uInt32 data; #ifndef UNSAFE_OPTIMIZATIONS - if((addr > 0x40001fff) && (addr < 0x50000000)) + if((addr > 0x40007fff) && (addr < 0x50000000)) fatalError("read16", addr, "abort - out of range"); - else if((addr > 0x7fff) && (addr < 0x10000000)) + else if((addr > 0x0007ffff) && (addr < 0x10000000)) fatalError("read16", addr, "abort - out of range"); if(addr & 1) fatalError("read16", addr, "abort - misaligned"); @@ -1424,6 +1429,7 @@ int Thumbulator::execute() case ConfigureFor::CDF1: case ConfigureFor::CDFJ: + case ConfigureFor::CDFJplus: // this subroutine interface is used in the CDF driver, // it starts at address 0x00000750 // _SetNote: @@ -2521,25 +2527,10 @@ int Thumbulator::execute() int Thumbulator::reset() { reg_norm.fill(0); - reg_norm[13] = 0x40001FB4; - switch(configuration) - { - // future 2K Harmony/Melody drivers will most likely use these settings - case ConfigureFor::BUS: - case ConfigureFor::CDF: - case ConfigureFor::CDF1: - case ConfigureFor::CDFJ: - reg_norm[14] = 0x00000800; // Link Register - reg_norm[15] = 0x0000080B; // Program Counter - break; - - // future 3K Harmony/Melody drivers will most likely use these settings - case ConfigureFor::DPCplus: - reg_norm[14] = 0x00000C00; // Link Register - reg_norm[15] = 0x00000C0B; // Program Counter - break; - } + reg_norm[13] = cStack; // SP + reg_norm[14] = cBase; // LR + reg_norm[15] = (cStart + 2) | 1; // PC (+2 for pipeline, lower bit for THUMB) cpsr = mamcr = 0; handler_mode = false; diff --git a/src/emucore/Thumbulator.hxx b/src/emucore/Thumbulator.hxx index ae62d1755..2fd043627 100644 --- a/src/emucore/Thumbulator.hxx +++ b/src/emucore/Thumbulator.hxx @@ -35,11 +35,11 @@ class Cartridge; #define NO_THUMB_STATS #endif -#define ROMADDMASK 0x7FFF -#define RAMADDMASK 0x1FFF +#define ROMADDMASK 0x7FFFF +#define RAMADDMASK 0x7FFF -#define ROMSIZE (ROMADDMASK+1) -#define RAMSIZE (RAMADDMASK+1) +#define ROMSIZE (ROMADDMASK+1) // 512KB +#define RAMSIZE (RAMADDMASK+1) // 32KB #define CPSR_N (1u<<31) #define CPSR_Z (1u<<30) @@ -55,11 +55,13 @@ class Thumbulator BUS, // cartridges of type BUS CDF, // cartridges of type CDF CDF1, // cartridges of type CDF version 1 - CDFJ, // cartrdiges of type CDFJ + CDFJ, // cartridges of type CDFJ + CDFJplus, // cartridges of type CDFJ+ DPCplus // cartridges of type DPC+ }; Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, uInt16 rom_size, + const uInt32 c_base, const uInt32 c_start, const uInt32 c_stack, bool traponfatal, Thumbulator::ConfigureFor configurefor, Cartridge* cartridge); @@ -187,9 +189,11 @@ class Thumbulator private: const uInt16* rom{nullptr}; uInt16 romSize{0}; + uInt32 cBase{0}; + uInt32 cStart{0}; + uInt32 cStack{0}; const unique_ptr decodedRom; // NOLINT uInt16* ram{nullptr}; - std::array reg_norm; // normal execution mode, do not have a thread mode uInt32 cpsr{0}, mamcr{0}; bool handler_mode{false};