Updated CDFJ+ with support for LDX # and LDY # fast fetchers, as well as a fast fetcher offset value. Also updates to the CDF Debugger. (#877)

This commit is contained in:
Darrell Spice, Jr 2022-02-22 01:56:47 -06:00 committed by GitHub
parent 313b6c6c98
commit 7b026e6ad1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 1350 additions and 1237 deletions

View File

@ -31,7 +31,16 @@ CartridgeCDFInfoWidget::CartridgeCDFInfoWidget(
<< "Seven 4K banks are available to 2600\n" << "Seven 4K banks are available to 2600\n"
<< "Functions accessible @ $FFF0 - $FFF3\n" << "Functions accessible @ $FFF0 - $FFF3\n"
<< (cart.isCDFJplus() ? "Banks accessible @ $FFF4 to $FFFA\n" : "Banks accessible @ $FFF5 to $FFFB\n") << (cart.isCDFJplus() ? "Banks accessible @ $FFF4 to $FFFA\n" : "Banks accessible @ $FFF5 to $FFFB\n")
<< "Startup bank = " << cart.startBank() << "\n"; << "Startup bank = " << cart.startBank() << "\n"
<< "Fast Fetcher(s): LDA #";
if (cart.myLDXenabled)
info << ", LDX #";
if (cart.myLDYenabled)
info << ", LDY #";
info << "\n";
#if 0 #if 0
// Eventually, we should query this from the debugger/disassembler // Eventually, we should query this from the debugger/disassembler

View File

@ -67,6 +67,21 @@ CartridgeCDFWidget::CartridgeCDFWidget(
int lwidth; int lwidth;
// Fast Fetch Offset
if (isCDFJplus())
{
ypos += myLineHeight + VGAP;
new StaticTextWidget(_boss, _font, myFastFetch->getLeft(), ypos, "Fast Fetch Offset: ");
lwidth = _font.getStringWidth("Fast Fetch Offset: ");
myFastFetcherOffset = new DataGridWidget(boss, _nfont, myFastFetch->getLeft() + lwidth, ypos, 1, 1, 2, 8,
Common::Base::Fmt::_16_2);
myFastFetcherOffset->setTarget(this);
myFastFetcherOffset->setEditable(false);
}
// Datastream Pointers // Datastream Pointers
#define DS_X (HBORDER + _font.getStringWidth("xx ")) #define DS_X (HBORDER + _font.getStringWidth("xx "))
xpos = DS_X; xpos = DS_X;
@ -208,8 +223,9 @@ CartridgeCDFWidget::CartridgeCDFWidget(
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCDFWidget::saveOldState() void CartridgeCDFWidget::saveOldState()
{ {
myOldState.tops.clear(); Int32 ds_shift = isCDFJplus() ? 8 : 12;
myOldState.bottoms.clear();
myOldState.fastfetchoffset.clear();
myOldState.datastreampointers.clear(); myOldState.datastreampointers.clear();
myOldState.datastreamincrements.clear(); myOldState.datastreamincrements.clear();
myOldState.addressmaps.clear(); myOldState.addressmaps.clear();
@ -220,6 +236,10 @@ void CartridgeCDFWidget::saveOldState()
myOldState.internalram.clear(); myOldState.internalram.clear();
myOldState.samplepointer.clear(); myOldState.samplepointer.clear();
if (isCDFJplus())
myOldState.fastfetchoffset.push_back(myCart.myRAM[myCart.myFastFetcherOffset]);
for(uInt32 i = 0; i < static_cast<uInt32>((isCDFJ() || isCDFJplus()) ? 35 : 34); ++i) for(uInt32 i = 0; i < static_cast<uInt32>((isCDFJ() || isCDFJplus()) ? 35 : 34); ++i)
{ {
// Pointers are stored as: // Pointers are stored as:
@ -232,7 +252,7 @@ void CartridgeCDFWidget::saveOldState()
// I = Increment // I = Increment
// F = Fractional // F = Fractional
myOldState.datastreampointers.push_back(myCart.getDatastreamPointer(i)>>12); myOldState.datastreampointers.push_back(myCart.getDatastreamPointer(i)>>ds_shift);
myOldState.datastreamincrements.push_back(myCart.getDatastreamIncrement(i)); myOldState.datastreamincrements.push_back(myCart.getDatastreamIncrement(i));
} }
@ -257,6 +277,7 @@ void CartridgeCDFWidget::saveOldState()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCDFWidget::loadConfig() void CartridgeCDFWidget::loadConfig()
{ {
Int32 ds_shift = isCDFJplus() ? 8 : 12;
myBank->setSelectedIndex(myCart.getBank()); myBank->setSelectedIndex(myCart.getBank());
// Get registers, using change tracking // Get registers, using change tracking
@ -264,11 +285,21 @@ void CartridgeCDFWidget::loadConfig()
IntArray vlist; IntArray vlist;
BoolArray changed; BoolArray changed;
if (isCDFJplus())
{
alist.clear(); vlist.clear(); changed.clear();
alist.push_back(0); vlist.push_back(myCart.myRAM[myCart.myFastFetcherOffset]);
changed.push_back((myCart.myRAM[myCart.myFastFetcherOffset]) != uInt32(myOldState.fastfetchoffset[0]));
myFastFetcherOffset->setList(alist, vlist, changed);
}
alist.clear(); vlist.clear(); changed.clear(); alist.clear(); vlist.clear(); changed.clear();
for(int i = 0; i < 32; ++i) for(int i = 0; i < 32; ++i)
{ {
// Pointers are stored as: // Pointers are stored as:
// PPPFF--- // PPPFF--- CDFJ
// PPPPFF-- CDFJ+
// //
// Increments are stored as // Increments are stored as
// ----IIFF // ----IIFF
@ -277,7 +308,7 @@ void CartridgeCDFWidget::loadConfig()
// I = Increment // I = Increment
// F = Fractional // F = Fractional
Int32 pointervalue = myCart.getDatastreamPointer(i) >> 12; Int32 pointervalue = myCart.getDatastreamPointer(i) >> ds_shift;
alist.push_back(0); vlist.push_back(pointervalue); alist.push_back(0); vlist.push_back(pointervalue);
changed.push_back(pointervalue != myOldState.datastreampointers[i]); changed.push_back(pointervalue != myOldState.datastreampointers[i]);
} }
@ -286,21 +317,21 @@ void CartridgeCDFWidget::loadConfig()
alist.clear(); vlist.clear(); changed.clear(); alist.clear(); vlist.clear(); changed.clear();
for(int i = 32; i < 34; ++i) for(int i = 32; i < 34; ++i)
{ {
Int32 pointervalue = myCart.getDatastreamPointer(i) >> 12; Int32 pointervalue = myCart.getDatastreamPointer(i) >> ds_shift;
alist.push_back(0); vlist.push_back(pointervalue); alist.push_back(0); vlist.push_back(pointervalue);
changed.push_back(pointervalue != myOldState.datastreampointers[i]); changed.push_back(pointervalue != myOldState.datastreampointers[i]);
} }
alist.clear(); vlist.clear(); changed.clear(); alist.clear(); vlist.clear(); changed.clear();
alist.push_back(0); alist.push_back(0);
vlist.push_back(myCart.getDatastreamPointer(0x20) >> 12); vlist.push_back(myCart.getDatastreamPointer(0x20) >> ds_shift);
changed.push_back(static_cast<Int32>(myCart.getDatastreamPointer(0x20)) != myOldState.datastreampointers[0x20]); changed.push_back(static_cast<Int32>(myCart.getDatastreamPointer(0x20)) != myOldState.datastreampointers[0x20]);
myCommandStreamPointer->setList(alist, vlist, changed); myCommandStreamPointer->setList(alist, vlist, changed);
alist.clear(); vlist.clear(); changed.clear(); alist.clear(); vlist.clear(); changed.clear();
for(int i = 0; i < ((isCDFJ() || isCDFJplus()) ? 2 : 1); ++i) for(int i = 0; i < ((isCDFJ() || isCDFJplus()) ? 2 : 1); ++i)
{ {
Int32 pointervalue = myCart.getDatastreamPointer(0x21 + i) >> 12; Int32 pointervalue = myCart.getDatastreamPointer(0x21 + i) >> ds_shift;
alist.push_back(0); vlist.push_back(pointervalue); alist.push_back(0); vlist.push_back(pointervalue);
changed.push_back(pointervalue != myOldState.datastreampointers[0x21 + i]); changed.push_back(pointervalue != myOldState.datastreampointers[0x21 + i]);
} }
@ -324,7 +355,7 @@ void CartridgeCDFWidget::loadConfig()
alist.clear(); vlist.clear(); changed.clear(); alist.clear(); vlist.clear(); changed.clear();
for(int i = 0; i < ((isCDFJ() || isCDFJplus()) ? 2 : 1); ++i) for(int i = 0; i < ((isCDFJ() || isCDFJplus()) ? 2 : 1); ++i)
{ {
Int32 pointervalue = myCart.getDatastreamIncrement(0x21 + i) >> 12; Int32 pointervalue = myCart.getDatastreamIncrement(0x21 + i) >> ds_shift;
alist.push_back(0); vlist.push_back(pointervalue); alist.push_back(0); vlist.push_back(pointervalue);
changed.push_back(pointervalue != myOldState.datastreamincrements[0x21 + i]); changed.push_back(pointervalue != myOldState.datastreamincrements[0x21 + i]);
} }

View File

@ -39,8 +39,7 @@ class CartridgeCDFWidget : public CartridgeARMWidget
private: private:
struct CartState { struct CartState {
ByteArray tops; ByteArray fastfetchoffset;
ByteArray bottoms;
IntArray datastreampointers; IntArray datastreampointers;
IntArray datastreamincrements; IntArray datastreamincrements;
IntArray addressmaps; IntArray addressmaps;
@ -67,6 +66,7 @@ class CartridgeCDFWidget : public CartridgeARMWidget
DataGridWidget* myMusicWaveforms{nullptr}; DataGridWidget* myMusicWaveforms{nullptr};
DataGridWidget* myMusicWaveformSizes{nullptr}; DataGridWidget* myMusicWaveformSizes{nullptr};
DataGridWidget* mySamplePointer{nullptr}; DataGridWidget* mySamplePointer{nullptr};
DataGridWidget* myFastFetcherOffset{nullptr};
std::array<StaticTextWidget*, 10> myDatastreamLabels{nullptr}; std::array<StaticTextWidget*, 10> myDatastreamLabels{nullptr};
CheckboxWidget* myFastFetch{nullptr}; CheckboxWidget* myFastFetch{nullptr};

View File

@ -34,10 +34,10 @@
#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] + \ #define getUInt32(_array, _address) (unsigned int)((_array)[(_address) + 0] + \
((_array)[(_address) + 1] << 8) + \ ((_array)[(_address) + 1] << 8) + \
((_array)[(_address) + 2] << 16) + \ ((_array)[(_address) + 2] << 16) + \
((_array)[(_address) + 3] << 24)) ((_array)[(_address) + 3] << 24))
namespace { namespace {
Thumbulator::ConfigureFor thumulatorConfiguration(CartridgeCDF::CDFSubtype subtype) Thumbulator::ConfigureFor thumulatorConfiguration(CartridgeCDF::CDFSubtype subtype)
@ -151,7 +151,7 @@ void CartridgeCDF::setInitialState()
// need to confirm with Chris // need to confirm with Chris
myMode = 0xFF; myMode = 0xFF;
myBankOffset = myLDAimmediateOperandAddress = myJMPoperandAddress = 0; myBankOffset = myLDAXYimmediateOperandAddress = myJMPoperandAddress = 0;
myFastJumpActive = myFastJumpStream = 0; myFastJumpActive = myFastJumpStream = 0;
CartridgeARM::setInitialState(); CartridgeARM::setInitialState();
@ -277,12 +277,19 @@ uInt8 CartridgeCDF::peek(uInt16 address)
// Do a FAST FETCH LDA# if: // Do a FAST FETCH LDA# if:
// 1) in Fast Fetch mode // 1) in Fast Fetch mode
// 2) peeking the operand of an LDA # instruction // 2) peeking the operand of an LDA # instruction
// 3) peek value is 0-34 // 3) peek value is between myDSfetcherOffset and myDSfetcherOffset+34 inclusive
if(FAST_FETCH_ON bool fastfetch;
&& myLDAimmediateOperandAddress == address if (myFastFetcherOffset)
&& peekvalue <= myAmplitudeStream) fastfetch = (FAST_FETCH_ON && myLDAXYimmediateOperandAddress == address
&& peekvalue >= myRAM[myFastFetcherOffset] && peekvalue <= myRAM[myFastFetcherOffset]+myAmplitudeStream);
else
fastfetch = (FAST_FETCH_ON && myLDAXYimmediateOperandAddress == address
&& peekvalue >= 0 && peekvalue <= myAmplitudeStream);
if (fastfetch)
{ {
myLDAimmediateOperandAddress = 0; myLDAXYimmediateOperandAddress = 0;
if (myFastFetcherOffset)
peekvalue -= myRAM[myFastFetcherOffset]; // normalize peekvalue to 0 - 35
if (peekvalue == myAmplitudeStream) if (peekvalue == myAmplitudeStream)
{ {
updateMusicModeDataFetchers(); updateMusicModeDataFetchers();
@ -319,7 +326,7 @@ uInt8 CartridgeCDF::peek(uInt16 address)
return readFromDatastream(peekvalue); return readFromDatastream(peekvalue);
} }
} }
myLDAimmediateOperandAddress = 0; myLDAXYimmediateOperandAddress = 0;
// Switch banks if necessary // Switch banks if necessary
switch(address) switch(address)
@ -360,8 +367,13 @@ uInt8 CartridgeCDF::peek(uInt16 address)
break; break;
} }
if(FAST_FETCH_ON && peekvalue == 0xA9) if (FAST_FETCH_ON)
myLDAimmediateOperandAddress = address + 1; {
if ((peekvalue == 0xA9) ||
(myLDXenabled && peekvalue == 0xA2 ) ||
(myLDYenabled && peekvalue == 0xA0))
myLDAXYimmediateOperandAddress = address + 1;
}
return peekvalue; return peekvalue;
} }
@ -562,7 +574,7 @@ bool CartridgeCDF::save(Serializer& out) const
out.putByte(myFastJumpActive); out.putByte(myFastJumpActive);
// operand addresses // operand addresses
out.putShort(myLDAimmediateOperandAddress); out.putShort(myLDAXYimmediateOperandAddress);
out.putShort(myJMPoperandAddress); out.putShort(myJMPoperandAddress);
// Harmony RAM // Harmony RAM
@ -604,7 +616,7 @@ bool CartridgeCDF::load(Serializer& in)
myFastJumpActive = in.getByte(); myFastJumpActive = in.getByte();
// Address of LDA # operand // Address of LDA # operand
myLDAimmediateOperandAddress = in.getShort(); myLDAXYimmediateOperandAddress = in.getShort();
myJMPoperandAddress = in.getShort(); myJMPoperandAddress = in.getShort();
// Harmony RAM // Harmony RAM
@ -735,20 +747,58 @@ uInt8 CartridgeCDF::readFromDatastream(uInt8 index)
return value; return value;
} }
// params:
// - searchValue: uInt32 value to search for; assumes it is on a DWORD boundary
//
// returns:
// - offset in image where value was found
// - 0xFFFFFFFF if not found
uInt32 CartridgeCDF::scanCDFDriver(uInt32 searchValue)
{
for (int i = 0; i < 2048; i += 4)
{
if (getUInt32(myImage.get(), i) == searchValue)
{
return i;
}
}
return 0xFFFFFFFF;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeCDF::setupVersion() void CartridgeCDF::setupVersion()
{ {
// CDFJ+ detection // CDFJ+ detection
if (getUInt32(myImage.get(), 0x174) == 0x53554c50 && // Plus
getUInt32(myImage.get(), 0x178) == 0x4a464443 && // CDFJ
getUInt32(myImage.get(), 0x17C) == 0x00000001) { // V1
// get offset of CDFJPlus ID
uInt32 cdfjOffset;
if ((cdfjOffset = scanCDFDriver(0x53554c50)) != 0xFFFFFFFF && // Plus
getUInt32(myImage.get(), cdfjOffset+4) == 0x4a464443 && // CDFJ
getUInt32(myImage.get(), cdfjOffset+8) == 0x00000001) { // V1
myCDFSubtype = CDFSubtype::CDFJplus; myCDFSubtype = CDFSubtype::CDFJplus;
myAmplitudeStream = 0x23; myAmplitudeStream = 0x23;
myFastjumpStreamIndexMask = 0xfe; myFastjumpStreamIndexMask = 0xfe;
myDatastreamBase = 0x0098; myDatastreamBase = 0x0098;
myDatastreamIncrementBase = 0x0124; myDatastreamIncrementBase = 0x0124;
myFastFetcherOffset = 0;
myWaveformBase = 0x01b0; myWaveformBase = 0x01b0;
uInt32 cdfjValue;
for (int i=0; i<2048; i += 4)
{
cdfjValue = getUInt32(myImage.get(), i);
if (cdfjValue == 0x135200A2)
myLDXenabled = true;
if (cdfjValue == 0x135200A0)
myLDYenabled = true;
// search for Fast Fetcher Offset (default is 0)
if ((cdfjValue & 0xFFFFFF00) == 0xE2422000)
myFastFetcherOffset = i;
}
return; return;
} }

View File

@ -29,7 +29,7 @@ class System;
CDFJ bankswitching for Atari games using ARM/C code. CDFJ bankswitching for Atari games using ARM/C code.
There are two variants supported: There are two variants supported:
1) CDF/CDFJ - initial scheme with 32K ROM and 8K RAM 1) CDF/CDFJ - initial scheme with 32K ROM and 8K RAM
2) CDFJ+ - support for larger ROM sizes (64/128/256/512K) and RAM sizes (16/32K) 2) CDFJ+ - adds support for larger ROM sizes (64/128/256/512K) and RAM sizes (16/32K)
Features: Features:
32 fast fetchers 32 fast fetchers
@ -39,8 +39,15 @@ class System;
7 banks (4K) of atari code 7 banks (4K) of atari code
4K display data (16K and 32K available with CDFJ+) 4K display data (16K and 32K available with CDFJ+)
Note that for CDFJ+, the same driver is used for all RAM/RAM combinations. Note that for CDFJ+ the programmer must ensure that only the available RAM/ROM on the target device is
It is left to the programmer to ensure that only the available RAM/ROM on the target device is used. used. There are 2 versions of the driver, with minor changes due to hardware.
1) 32K ROM and 8K RAM - compatible with 48-Pin LPC210X Family (Harmony, Harmony Encore, Melody)
2) 64/128/256/512K ROM and16/32K RAM - compatible with 64-Pin LPC213X Family
The CDFJ+ driver can be modified to also override LDX # and LDY # for fast fetcher use. Additionally
an offset can be set for the Fast Fetchers - if the offset was set to $80 then LDA #$85 would do a fast fetch
of datastream 5. As implemented Stella's CDFJ+ support expects these to have been set in the driver ahead
of time, though In theory they could be done at run time.
Bankswitching Note: Bankswitching Note:
CDF/CDFJ uses $FFF5 through $FFFB (initial bank 6) CDF/CDFJ uses $FFF5 through $FFFB (initial bank 6)
@ -253,6 +260,8 @@ class CartridgeCDF : public CartridgeARM
uInt32 getSample(); uInt32 getSample();
void setupVersion(); void setupVersion();
uInt32 scanCDFDriver(uInt32 value);
/** /**
Answer whether this is a PlusROM cart. Note that until the Answer whether this is a PlusROM cart. Note that until the
initialize method has been called, this will always return false. initialize method has been called, this will always return false.
@ -330,8 +339,22 @@ class CartridgeCDF : public CartridgeARM
// F- = 3 Voice Music // F- = 3 Voice Music
uInt8 myMode{0xFF}; uInt8 myMode{0xFF};
// set to address of #value if last byte peeked was A9 (LDA #) // set to address of #value if last byte peeked was A9 (LDA #),
uInt16 myLDAimmediateOperandAddress{0}; // or for CDFJ+ variations if A0 (LDY #) or A2 (LDX #)
uInt16 myLDAXYimmediateOperandAddress{0};
// Some CDFJ+ drivers also override LDX # and/or LDY # for fast fetcher
// use. These flag if this has been done.
bool myLDXenabled{false};
bool myLDYenabled{false};
// Some CDFJ+ drivers allow setting a fetcher base offset to allow
// immediate load of specific ranges. This is the location within the RAM
// copy of the CDFJ+ driver of the offset.
// ex. if 16, immedate lda #>=16 <=51 will trigger a FASTFETCH
// default is 0 so lda #>=0 <=35 will trigger a FASTFETCH
//
uInt16 myFastFetcherOffset{0};
// set to address of the JMP operand if last byte peeked was 4C // set to address of the JMP operand if last byte peeked was 4C
// *and* the next two bytes in ROM are 00 00 // *and* the next two bytes in ROM are 00 00