Preliminary support for CDFJ+ bankswitching

This commit is contained in:
cd-w 2020-09-13 13:16:34 -07:00
parent 40362ebc6c
commit 6d94f64b24
9 changed files with 219 additions and 123 deletions

View File

@ -23,16 +23,28 @@ CartridgeCDFInfoWidget::CartridgeCDFInfoWidget(
int x, int y, int w, int h, CartridgeCDF& cart) int x, int y, int w, int h, CartridgeCDF& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h) : CartDebugWidget(boss, lfont, nfont, x, y, w, h)
{ {
uInt16 size = 8 * 4096; uInt32 size;
ostringstream info; 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";
if (cart.myCDFSubtype == CartridgeCDF::CDFSubtype::CDFJplus) {
size = 512 * 1024;
info << describeCDFVersion(cart.myCDFSubtype) << " cartridge\n"
<< "512K ROM (seven 4K banks are accessible to 2600)\n"
<< "32K RAM\n"
<< "Functions accessible @ $FFF0 - $FFF3\n"
<< "Banks accessible @ $FFF4 to $FFFB\n"
<< "Startup bank = " << cart.startBank() << "\n";
} else {
size = 8 * 4096;
info << describeCDFVersion(cart.myCDFSubtype) << " cartridge\n"
<< "32K ROM (seven 4K banks are accessible to 2600)\n"
<< "8K RAM\n"
<< "Functions accessible @ $FFF0 - $FFF3\n"
<< "Banks accessible @ $FFF4 to $FFFB\n"
<< "Startup bank = " << cart.startBank() << "\n";
}
#if 0 #if 0
// Eventually, we should query this from the debugger/disassembler // Eventually, we should query this from the debugger/disassembler
for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF5; i < 7; ++i, offset += 0x1000) for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF5; i < 7; ++i, offset += 0x1000)
@ -61,6 +73,9 @@ string CartridgeCDFInfoWidget::describeCDFVersion(CartridgeCDF::CDFSubtype subty
case CartridgeCDF::CDFSubtype::CDFJ: case CartridgeCDF::CDFSubtype::CDFJ:
return "CDFJ"; return "CDFJ";
case CartridgeCDF::CDFSubtype::CDFJplus:
return "CDFJ+";
default: default:
throw runtime_error("unreachable"); throw runtime_error("unreachable");
} }

View File

@ -467,6 +467,9 @@ string CartridgeCDFWidget::describeCDFVersion(CartridgeCDF::CDFSubtype subtype)
case CartridgeCDF::CDFSubtype::CDFJ: case CartridgeCDF::CDFSubtype::CDFJ:
return "CDFJ"; return "CDFJ";
case CartridgeCDF::CDFSubtype::CDFJplus:
return "CDFJ+";
default: default:
throw runtime_error("unreachable"); throw runtime_error("unreachable");
} }
@ -475,5 +478,6 @@ string CartridgeCDFWidget::describeCDFVersion(CartridgeCDF::CDFSubtype subtype)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeCDFWidget::isCDFJ() const bool CartridgeCDFWidget::isCDFJ() const
{ {
return myCart.myCDFSubtype == CartridgeCDF::CDFSubtype::CDFJ; return (myCart.myCDFSubtype == CartridgeCDF::CDFSubtype::CDFJ ||
myCart.myCDFSubtype == CartridgeCDF::CDFSubtype::CDFJplus); // FIXME: Separate settings for CDFJ+
} }

View File

@ -68,8 +68,12 @@ CartridgeBUS::CartridgeBUS(const ByteBuffer& image, size_t size,
reinterpret_cast<uInt16*>(myImage.get()), reinterpret_cast<uInt16*>(myImage.get()),
reinterpret_cast<uInt16*>(myRAM.data()), reinterpret_cast<uInt16*>(myRAM.data()),
static_cast<uInt32>(32_KB), static_cast<uInt32>(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(); setInitialState();
} }

View File

@ -29,14 +29,17 @@
#include "TIA.hxx" #include "TIA.hxx"
#include "exception/FatalEmulationError.hxx" #include "exception/FatalEmulationError.hxx"
#define DSRAM 0x0800
#define COMMSTREAM 0x20 #define COMMSTREAM 0x20
#define JUMPSTREAM_BASE 0x21 #define JUMPSTREAM_BASE 0x21
#define FAST_FETCH_ON ((myMode & 0x0F) == 0) #define FAST_FETCH_ON ((myMode & 0x0F) == 0)
#define DIGITAL_AUDIO_ON ((myMode & 0xF0) == 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 { namespace {
Thumbulator::ConfigureFor thumulatorConfiguration(CartridgeCDF::CDFSubtype subtype) Thumbulator::ConfigureFor thumulatorConfiguration(CartridgeCDF::CDFSubtype subtype)
{ {
@ -50,6 +53,9 @@ namespace {
case CartridgeCDF::CDFSubtype::CDFJ: case CartridgeCDF::CDFSubtype::CDFJ:
return Thumbulator::ConfigureFor::CDFJ; return Thumbulator::ConfigureFor::CDFJ;
case CartridgeCDF::CDFSubtype::CDFJplus:
return Thumbulator::ConfigureFor::CDFJplus;
default: default:
throw runtime_error("unreachable"); throw runtime_error("unreachable");
} }
@ -60,34 +66,53 @@ namespace {
CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size, CartridgeCDF::CartridgeCDF(const ByteBuffer& image, size_t size,
const string& md5, const Settings& settings) const string& md5, const Settings& settings)
: Cartridge(settings, md5), : Cartridge(settings, md5),
myImage(make_unique<uInt8[]>(32_KB)) myImage(make_unique<uInt8[]>(512_KB))
{ {
// Copy the ROM image into my buffer // Copy the ROM image into my buffer
std::fill_n(myImage.get(), 32_KB, 0); std::fill_n(myImage.get(), 512_KB, 0);
std::copy_n(image.get(), std::min(32_KB, size), myImage.get()); 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 // Detect cart version
createRomAccessArrays(28_KB); setupVersion();
// Pointer to the program ROM (28K @ 0 byte offset) // CDFJ+ has different settings
// which starts after the 2K CDF Driver and 2K C Code bool cdfjPlus = (myCDFSubtype == CDFSubtype::CDFJplus);
myProgramImage = myImage.get() + 4_KB;
// The lowest 2K is not accessible to the debugger
createRomAccessArrays(cdfjPlus ? 510_KB : 28_KB);
// Pointer to the program ROM
// which starts after the 2K driver (and 2K C Code for CDF)
myProgramImage = myImage.get() + (cdfjPlus ? 2_KB : 4_KB);
// Pointer to CDF driver in RAM // Pointer to CDF driver in RAM
myDriverImage = myRAM.data(); myDriverImage = myRAM.data();
// Pointer to the display RAM // Pointer to the display RAM (starts after 2K driver)
myDisplayImage = myRAM.data() + DSRAM; myDisplayImage = myRAM.data() + 2_KB;
setupVersion(); // C addresses
uInt32 cBase, cStart, cStack;
if (cdfjPlus) {
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 // Create Thumbulator ARM emulator
bool devSettings = settings.getBool("dev.settings"); bool devSettings = settings.getBool("dev.settings");
myThumbEmulator = make_unique<Thumbulator>( myThumbEmulator = make_unique<Thumbulator>(
reinterpret_cast<uInt16*>(myImage.get()), reinterpret_cast<uInt16*>(myImage.get()),
reinterpret_cast<uInt16*>(myRAM.data()), reinterpret_cast<uInt16*>(myRAM.data()),
static_cast<uInt32>(32_KB), static_cast<uInt32>(512_KB),
devSettings ? settings.getBool("dev.thumb.trapfatal") : false, thumulatorConfiguration(myCDFSubtype), this); cBase, cStart, cStack,
devSettings ? settings.getBool("dev.thumb.trapfatal") : false,
thumulatorConfiguration(myCDFSubtype),
this);
setInitialState(); setInitialState();
} }
@ -97,8 +122,8 @@ void CartridgeCDF::reset()
{ {
initializeRAM(myRAM.data()+2_KB, myRAM.size()-2_KB); initializeRAM(myRAM.data()+2_KB, myRAM.size()-2_KB);
// CDF always starts in bank 6 // CDF always starts in bank 6, CDFJ+ in bank 0
initializeStartBank(6); initializeStartBank((myCDFSubtype == CDFSubtype::CDFJplus) ? 0 : 6);
myAudioCycles = myARMCycles = 0; myAudioCycles = myARMCycles = 0;
myFractionalClocks = 0.0; myFractionalClocks = 0.0;
@ -123,7 +148,6 @@ void CartridgeCDF::setInitialState()
myBankOffset = myLDAimmediateOperandAddress = myJMPoperandAddress = 0; myBankOffset = myLDAimmediateOperandAddress = myJMPoperandAddress = 0;
myFastJumpActive = myFastJumpStream = 0; myFastJumpActive = myFastJumpStream = 0;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -194,8 +218,9 @@ inline void CartridgeCDF::callFunction(uInt8 value)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
uInt8 CartridgeCDF::peek(uInt16 address) uInt8 CartridgeCDF::peek(uInt16 address)
{ {
address &= 0x0FFF; bool cdfjPlus = (myCDFSubtype == CDFSubtype::CDFJplus);
address &= 0x0FFF;
uInt8 peekvalue = myProgramImage[myBankOffset + address]; uInt8 peekvalue = myProgramImage[myBankOffset + address];
// In debugger/bank-locked mode, we ignore all hotspots and in general // In debugger/bank-locked mode, we ignore all hotspots and in general
@ -214,8 +239,14 @@ uInt8 CartridgeCDF::peek(uInt16 address)
++myJMPoperandAddress; ++myJMPoperandAddress;
pointer = getDatastreamPointer(myFastJumpStream); pointer = getDatastreamPointer(myFastJumpStream);
value = myDisplayImage[ pointer >> 20 ]; if (cdfjPlus) {
pointer += 0x100000; // always increment by 1 value = myDisplayImage[ pointer >> 16 ];
pointer += 0x00010000; // always increment by 1
} else {
value = myDisplayImage[ pointer >> 20 ];
pointer += 0x00100000; // always increment by 1
}
setDatastreamPointer(myFastJumpStream, pointer); setDatastreamPointer(myFastJumpStream, pointer);
return value; return value;
@ -254,9 +285,9 @@ uInt8 CartridgeCDF::peek(uInt16 address)
uInt32 sampleaddress = getSample() + (myMusicCounters[0] >> 21); uInt32 sampleaddress = getSample() + (myMusicCounters[0] >> 21);
// get sample value from ROM or RAM // get sample value from ROM or RAM
if (sampleaddress < 0x8000) if (sampleaddress < 0x00080000)
peekvalue = myImage[sampleaddress]; 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]; peekvalue = myRAM[sampleaddress - 0x40000000];
else else
peekvalue = 0; peekvalue = 0;
@ -284,39 +315,36 @@ uInt8 CartridgeCDF::peek(uInt16 address)
// Switch banks if necessary // Switch banks if necessary
switch(address) switch(address)
{ {
case 0xFF5: case 0x0FF4:
// Set the current bank to the first 4k bank bank(cdfjPlus ? 0 : 6);
bank(0); break;
case 0x0FF5:
bank(cdfjPlus ? 1 : 0);
break; break;
case 0x0FF6: case 0x0FF6:
// Set the current bank to the second 4k bank bank(cdfjPlus ? 2 : 1);
bank(1);
break; break;
case 0x0FF7: case 0x0FF7:
// Set the current bank to the third 4k bank bank(cdfjPlus ? 3 : 2);
bank(2);
break; break;
case 0x0FF8: case 0x0FF8:
// Set the current bank to the fourth 4k bank bank(cdfjPlus ? 4 : 3);
bank(3);
break; break;
case 0x0FF9: case 0x0FF9:
// Set the current bank to the fifth 4k bank bank(cdfjPlus ? 5 : 4);
bank(4);
break; break;
case 0x0FFA: case 0x0FFA:
// Set the current bank to the sixth 4k bank bank(cdfjPlus ? 6 : 5);
bank(5);
break; break;
case 0x0FFB: case 0x0FFB:
// Set the current bank to the last 4k bank bank(cdfjPlus ? 0 : 6);
bank(6);
break; break;
default: default:
@ -333,67 +361,74 @@ uInt8 CartridgeCDF::peek(uInt16 address)
bool CartridgeCDF::poke(uInt16 address, uInt8 value) bool CartridgeCDF::poke(uInt16 address, uInt8 value)
{ {
uInt32 pointer; uInt32 pointer;
bool cdfjPlus = (myCDFSubtype == CDFSubtype::CDFJplus);
address &= 0x0FFF; address &= 0x0FFF;
switch(address) switch(address)
{ {
case 0xFF0: // DSWRITE case 0x0FF0: // DSWRITE
pointer = getDatastreamPointer(COMMSTREAM); pointer = getDatastreamPointer(COMMSTREAM);
myDisplayImage[ pointer >> 20 ] = value; if (cdfjPlus) {
pointer += 0x100000; // always increment by 1 when writing 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); setDatastreamPointer(COMMSTREAM, pointer);
break; break;
case 0xFF1: // DSPTR case 0x0FF1: // DSPTR
pointer = getDatastreamPointer(COMMSTREAM); pointer = getDatastreamPointer(COMMSTREAM);
pointer <<=8; pointer <<= 8;
pointer &= 0xf0000000; if (cdfjPlus) {
pointer |= (value << 20); pointer &= 0xff000000;
pointer |= (value << 16);
} else {
pointer &= 0xf0000000;
pointer |= (value << 20);
}
setDatastreamPointer(COMMSTREAM, pointer); setDatastreamPointer(COMMSTREAM, pointer);
break; break;
case 0xFF2: // SETMODE case 0x0FF2: // SETMODE
myMode = value; myMode = value;
break; break;
case 0xFF3: // CALLFN case 0x0FF3: // CALLFN
callFunction(value); callFunction(value);
break; break;
case 0xFF5: case 0x00FF4:
// Set the current bank to the first 4k bank bank(cdfjPlus ? 0 : 6);
bank(0); break;
case 0x0FF5:
bank(cdfjPlus ? 1 : 0);
break; break;
case 0x0FF6: case 0x0FF6:
// Set the current bank to the second 4k bank bank(cdfjPlus ? 2 : 1);
bank(1);
break; break;
case 0x0FF7: case 0x0FF7:
// Set the current bank to the third 4k bank bank(cdfjPlus ? 3 : 2);
bank(2);
break; break;
case 0x0FF8: case 0x0FF8:
// Set the current bank to the fourth 4k bank bank(cdfjPlus ? 4 : 3);
bank(3);
break; break;
case 0x0FF9: case 0x0FF9:
// Set the current bank to the fifth 4k bank bank(cdfjPlus ? 5 : 4);
bank(4);
break; break;
case 0x0FFA: case 0x0FFA:
// Set the current bank to the sixth 4k bank bank(cdfjPlus ? 6 : 5);
bank(5);
break; break;
case 0x0FFB: case 0x0FFB:
// Set the current bank to the last 4k bank bank(cdfjPlus ? 0 : 6);
bank(6);
break; break;
default: default:
@ -419,7 +454,7 @@ bool CartridgeCDF::bank(uInt16 bank, uInt16)
{ {
access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)]; access.romAccessBase = &myRomAccessBase[myBankOffset + (addr & 0x0FFF)];
access.romPeekCounter = &myRomAccessCounter[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); mySystem->setPageAccess(addr, access);
} }
return myBankChanged = true; return myBankChanged = true;
@ -455,7 +490,7 @@ bool CartridgeCDF::patch(uInt16 address, uInt8 value)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const ByteBuffer& CartridgeCDF::getImage(size_t& size) const const ByteBuffer& CartridgeCDF::getImage(size_t& size) const
{ {
size = 32_KB; size = 512_KB;
return myImage; return myImage;
} }
@ -617,11 +652,13 @@ uInt32 CartridgeCDF::getWaveform(uInt8 index) const
(myRAM[address + 2] << 16) + (myRAM[address + 2] << 16) +
(myRAM[address + 3] << 24); // high byte (myRAM[address + 3] << 24); // high byte
result -= (0x40000000 + DSRAM); result -= (0x40000000 + 2_KB);
if (result >= 4096)
result &= 4095;
if (myCDFSubtype != CDFSubtype::CDFJplus) {
if (result >= 4096) {
result &= 4095;
}
}
return result; return result;
} }
@ -659,8 +696,17 @@ uInt8 CartridgeCDF::readFromDatastream(uInt8 index)
uInt32 pointer = getDatastreamPointer(index); uInt32 pointer = getDatastreamPointer(index);
uInt16 increment = getDatastreamIncrement(index); uInt16 increment = getDatastreamIncrement(index);
uInt8 value = myDisplayImage[ pointer >> 20 ];
pointer += (increment << 12); uInt8 value;
bool cdfjPlus = (myCDFSubtype == CDFSubtype::CDFJplus);
if (cdfjPlus) {
value = myDisplayImage[ pointer >> 16 ];
pointer += (increment << 8);
} else {
value = myDisplayImage[ pointer >> 20 ];
pointer += (increment << 12);
}
setDatastreamPointer(index, pointer); setDatastreamPointer(index, pointer);
return value; return value;
} }
@ -668,8 +714,21 @@ uInt8 CartridgeCDF::readFromDatastream(uInt8 index)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCDF::setupVersion() 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) for(uInt32 i = 0; i < 2048; i += 4)
{ {
// CDF signature occurs 3 times in a row, i+3 (+7 or +11) is version // CDF signature occurs 3 times in a row, i+3 (+7 or +11) is version
@ -683,6 +742,7 @@ void CartridgeCDF::setupVersion()
} }
switch (subversion) { switch (subversion) {
case 0x4a: case 0x4a:
myCDFSubtype = CDFSubtype::CDFJ; myCDFSubtype = CDFSubtype::CDFJ;
@ -727,6 +787,8 @@ string CartridgeCDF::name() const
return "CartridgeCDF1"; return "CartridgeCDF1";
case CDFSubtype::CDFJ: case CDFSubtype::CDFJ:
return "CartridgeCDFJ"; return "CartridgeCDFJ";
case CDFSubtype::CDFJplus:
return "CartridgeCDFJplus";
default: default:
return "Cart unknown"; return "Cart unknown";
} }

View File

@ -25,16 +25,15 @@ class Thumbulator;
#include "Cart.hxx" #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, There are seven 4K program banks, a 4K Display Data RAM,
1K C Variable and Stack, and the CDF chip. 1K C Variable and Stack, and the CDF chip.
CDF chip access is mapped to $1000 - $103F (both read and write). 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 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 Stephen Anthony, Bradford W. Mott
*/ */
class CartridgeCDF : public Cartridge class CartridgeCDF : public Cartridge
@ -48,7 +47,8 @@ class CartridgeCDF : public Cartridge
enum class CDFSubtype { enum class CDFSubtype {
CDF0, CDF0,
CDF1, CDF1,
CDFJ CDFJ,
CDFJplus
}; };
public: public:
@ -220,23 +220,26 @@ class CartridgeCDF : public Cartridge
void setupVersion(); void setupVersion();
private: private:
// The 32K ROM image of the cartridge // The ROM image of the cartridge
ByteBuffer myImage; ByteBuffer myImage;
// Pointer to the 28K program ROM image of the cartridge // Pointer to the program ROM image of the cartridge
uInt8* myProgramImage{nullptr}; 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}; uInt8* myDisplayImage{nullptr};
// Pointer to the 2K CDF driver image in RAM // Pointer to the driver image in RAM
uInt8* myDriverImage{nullptr}; uInt8* myDriverImage{nullptr};
// The CDF 8k RAM image, used as: // The CDFJ 8K RAM image, used as:
// $0000 - 2K CDF driver // $0000 - 2K Driver
// $0800 - 4K Display Data // $0800 - 4K Display Data
// $1800 - 2K C Variable & Stack // $1800 - 2K C Variable & Stack
std::array<uInt8, 8_KB> myRAM; // For CDFJ+, used as:
// $0000 - 2K Driver
// $0800 - Display Data, C Variables & Stack
std::array<uInt8, 32_KB> myRAM;
// Pointer to the Thumb ARM emulator object // Pointer to the Thumb ARM emulator object
unique_ptr<Thumbulator> myThumbEmulator; unique_ptr<Thumbulator> myThumbEmulator;

View File

@ -54,6 +54,9 @@ CartridgeDPCPlus::CartridgeDPCPlus(const ByteBuffer& image, size_t size,
(reinterpret_cast<uInt16*>(myImage.get()), (reinterpret_cast<uInt16*>(myImage.get()),
reinterpret_cast<uInt16*>(myDPCRAM.data()), reinterpret_cast<uInt16*>(myDPCRAM.data()),
static_cast<uInt32>(32_KB), static_cast<uInt32>(32_KB),
0x00000C00,
0x00000C08,
0x40001FDC,
devSettings ? settings.getBool("dev.thumb.trapfatal") : false, devSettings ? settings.getBool("dev.thumb.trapfatal") : false,
Thumbulator::ConfigureFor::DPCplus, Thumbulator::ConfigureFor::DPCplus,
this); this);

View File

@ -169,6 +169,8 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si
type = Bankswitch::Type::_3E; type = Bankswitch::Type::_3E;
else if(isProbably3F(image, size)) else if(isProbably3F(image, size))
type = Bankswitch::Type::_3F; type = Bankswitch::Type::_3F;
else if (isProbablyCDF(image, size))
type = Bankswitch::Type::_CDF;
else if(isProbably4A50(image, size)) else if(isProbably4A50(image, size))
type = Bankswitch::Type::_4A50; type = Bankswitch::Type::_4A50;
else if(isProbablyEF(image, size, type)) 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 ; // type has been set directly in the function
else if(isProbably3F(image, size)) else if(isProbably3F(image, size))
type = Bankswitch::Type::_3F; type = Bankswitch::Type::_3F;
else if (isProbablyCDF(image, size))
type = Bankswitch::Type::_CDF;
else if(isProbably4A50(image, size)) else if(isProbably4A50(image, size))
type = Bankswitch::Type::_4A50; type = Bankswitch::Type::_4A50;
else /*if(isProbablySB(image, size))*/ 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 ; // type has been set directly in the function
else if(isProbably3F(image, size)) else if(isProbably3F(image, size))
type = Bankswitch::Type::_3F; type = Bankswitch::Type::_3F;
else if (isProbablyCDF(image, size))
type = Bankswitch::Type::_CDF;
else /*if(isProbablySB(image, size))*/ else /*if(isProbablySB(image, size))*/
type = Bankswitch::Type::_SB; type = Bankswitch::Type::_SB;
} }
@ -216,6 +222,8 @@ Bankswitch::Type CartDetector::autodetectType(const ByteBuffer& image, size_t si
type = Bankswitch::Type::_3E; type = Bankswitch::Type::_3E;
else if(isProbably3F(image, size)) else if(isProbably3F(image, size))
type = Bankswitch::Type::_3F; type = Bankswitch::Type::_3F;
else if (isProbablyCDF(image, size))
type = Bankswitch::Type::_CDF;
} }
else // what else can we do? 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 // Note: all Harmony/Melody custom drivers also contain the value
// 0x10adab1e (LOADABLE) if needed for future improvement // 0x10adab1e (LOADABLE) if needed for future improvement
uInt8 cdf[] = { 'C', 'D', 'F' }; 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));
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -54,10 +54,14 @@ using Common::Base;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Thumbulator::Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, uInt16 rom_size, 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, bool traponfatal, Thumbulator::ConfigureFor configurefor,
Cartridge* cartridge) Cartridge* cartridge)
: rom(rom_ptr), : rom(rom_ptr),
romSize(rom_size), romSize(rom_size),
cBase(c_base),
cStart(c_start),
cStack(c_stack),
decodedRom(make_unique<Op[]>(romSize / 2)), // NOLINT decodedRom(make_unique<Op[]>(romSize / 2)), // NOLINT
ram(ram_ptr), ram(ram_ptr),
configuration(configurefor), configuration(configurefor),
@ -217,7 +221,7 @@ uInt32 Thumbulator::fetch16(uInt32 addr)
void Thumbulator::write16(uInt32 addr, uInt32 data) void Thumbulator::write16(uInt32 addr, uInt32 data)
{ {
#ifndef UNSAFE_OPTIMIZATIONS #ifndef UNSAFE_OPTIMIZATIONS
if((addr > 0x40001fff) && (addr < 0x50000000)) if((addr > 0x40007fff) && (addr < 0x50000000))
fatalError("write16", addr, "abort - out of range"); fatalError("write16", addr, "abort - out of range");
if (isProtected(addr)) fatalError("write16", addr, "to driver area"); 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))); return (addr < 0x0800) && (addr > 0x0028) && !((addr >= 0x00a0) && (addr < (0x00a0 + 284)));
case ConfigureFor::CDFJ: case ConfigureFor::CDFJ:
case ConfigureFor::CDFJplus:
return (addr < 0x0800) && (addr > 0x0028) && !((addr >= 0x0098) && (addr < (0x0098 + 292))); return (addr < 0x0800) && (addr > 0x0028) && !((addr >= 0x0098) && (addr < (0x0098 + 292)));
case ConfigureFor::BUS: case ConfigureFor::BUS:
@ -391,9 +396,9 @@ uInt32 Thumbulator::read16(uInt32 addr)
{ {
uInt32 data; uInt32 data;
#ifndef UNSAFE_OPTIMIZATIONS #ifndef UNSAFE_OPTIMIZATIONS
if((addr > 0x40001fff) && (addr < 0x50000000)) if((addr > 0x40007fff) && (addr < 0x50000000))
fatalError("read16", addr, "abort - out of range"); 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"); fatalError("read16", addr, "abort - out of range");
if(addr & 1) if(addr & 1)
fatalError("read16", addr, "abort - misaligned"); fatalError("read16", addr, "abort - misaligned");
@ -1424,6 +1429,7 @@ int Thumbulator::execute()
case ConfigureFor::CDF1: case ConfigureFor::CDF1:
case ConfigureFor::CDFJ: case ConfigureFor::CDFJ:
case ConfigureFor::CDFJplus:
// this subroutine interface is used in the CDF driver, // this subroutine interface is used in the CDF driver,
// it starts at address 0x00000750 // it starts at address 0x00000750
// _SetNote: // _SetNote:
@ -2521,25 +2527,10 @@ int Thumbulator::execute()
int Thumbulator::reset() int Thumbulator::reset()
{ {
reg_norm.fill(0); reg_norm.fill(0);
reg_norm[13] = 0x40001FB4;
switch(configuration) reg_norm[13] = cStack; // SP
{ reg_norm[14] = cBase; // LR
// future 2K Harmony/Melody drivers will most likely use these settings reg_norm[15] = (cStart + 2) | 1; // PC (+2 for pipeline, lower bit for THUMB)
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;
}
cpsr = mamcr = 0; cpsr = mamcr = 0;
handler_mode = false; handler_mode = false;

View File

@ -35,11 +35,11 @@ class Cartridge;
#define NO_THUMB_STATS #define NO_THUMB_STATS
#endif #endif
#define ROMADDMASK 0x7FFF #define ROMADDMASK 0x7FFFF
#define RAMADDMASK 0x1FFF #define RAMADDMASK 0x7FFF
#define ROMSIZE (ROMADDMASK+1) #define ROMSIZE (ROMADDMASK+1) // 512KB
#define RAMSIZE (RAMADDMASK+1) #define RAMSIZE (RAMADDMASK+1) // 32KB
#define CPSR_N (1u<<31) #define CPSR_N (1u<<31)
#define CPSR_Z (1u<<30) #define CPSR_Z (1u<<30)
@ -55,11 +55,13 @@ class Thumbulator
BUS, // cartridges of type BUS BUS, // cartridges of type BUS
CDF, // cartridges of type CDF CDF, // cartridges of type CDF
CDF1, // cartridges of type CDF version 1 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+ DPCplus // cartridges of type DPC+
}; };
Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, uInt16 rom_size, 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, bool traponfatal, Thumbulator::ConfigureFor configurefor,
Cartridge* cartridge); Cartridge* cartridge);
@ -187,9 +189,11 @@ class Thumbulator
private: private:
const uInt16* rom{nullptr}; const uInt16* rom{nullptr};
uInt16 romSize{0}; uInt16 romSize{0};
uInt32 cBase{0};
uInt32 cStart{0};
uInt32 cStack{0};
const unique_ptr<Op[]> decodedRom; // NOLINT const unique_ptr<Op[]> decodedRom; // NOLINT
uInt16* ram{nullptr}; uInt16* ram{nullptr};
std::array<uInt32, 16> reg_norm; // normal execution mode, do not have a thread mode std::array<uInt32, 16> reg_norm; // normal execution mode, do not have a thread mode
uInt32 cpsr{0}, mamcr{0}; uInt32 cpsr{0}, mamcr{0};
bool handler_mode{false}; bool handler_mode{false};