mirror of https://github.com/stella-emu/stella.git
Merge pull request #703 from chrisdwalton/master
added CDFJ+ bankswitching
This commit is contained in:
commit
745e9dc934
|
@ -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/*
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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<uInt32>(isCDFJ() ? 35 : 34); ++i)
|
||||
for(uInt32 i = 0; i < static_cast<uInt32>((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<const char*, 7> spot = {
|
||||
"$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
||||
static constexpr std::array<const char*, 8> 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());
|
||||
}
|
|
@ -75,6 +75,7 @@ class CartridgeCDFWidget : public CartDebugWidget
|
|||
|
||||
private:
|
||||
bool isCDFJ() const;
|
||||
bool isCDFJplus() const;
|
||||
|
||||
static string describeCDFVersion(CartridgeCDF::CDFSubtype subtype);
|
||||
|
||||
|
|
|
@ -68,8 +68,12 @@ CartridgeBUS::CartridgeBUS(const ByteBuffer& image, size_t size,
|
|||
reinterpret_cast<uInt16*>(myImage.get()),
|
||||
reinterpret_cast<uInt16*>(myRAM.data()),
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -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<uInt8[]>(32_KB))
|
||||
myImage(make_unique<uInt8[]>(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<Thumbulator>(
|
||||
reinterpret_cast<uInt16*>(myImage.get()),
|
||||
reinterpret_cast<uInt16*>(myRAM.data()),
|
||||
static_cast<uInt32>(32_KB),
|
||||
devSettings ? settings.getBool("dev.thumb.trapfatal") : false, thumulatorConfiguration(myCDFSubtype), this);
|
||||
static_cast<uInt32>(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,
|
||||
|
|
|
@ -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<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
|
||||
unique_ptr<Thumbulator> myThumbEmulator;
|
||||
|
|
|
@ -54,6 +54,9 @@ CartridgeDPCPlus::CartridgeDPCPlus(const ByteBuffer& image, size_t size,
|
|||
(reinterpret_cast<uInt16*>(myImage.get()),
|
||||
reinterpret_cast<uInt16*>(myDPCRAM.data()),
|
||||
static_cast<uInt32>(32_KB),
|
||||
0x00000C00,
|
||||
0x00000C08,
|
||||
0x40001FDC,
|
||||
devSettings ? settings.getBool("dev.thumb.trapfatal") : false,
|
||||
Thumbulator::ConfigureFor::DPCplus,
|
||||
this);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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<Op[]>(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;
|
||||
|
|
|
@ -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<Op[]> decodedRom; // NOLINT
|
||||
uInt16* ram{nullptr};
|
||||
|
||||
std::array<uInt32, 16> reg_norm; // normal execution mode, do not have a thread mode
|
||||
uInt32 cpsr{0}, mamcr{0};
|
||||
bool handler_mode{false};
|
||||
|
|
Loading…
Reference in New Issue