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

@ -24,15 +24,24 @@ CartridgeCDFInfoWidget::CartridgeCDFInfoWidget(
: CartDebugWidget(boss, lfont, nfont, x, y, w, h) : CartDebugWidget(boss, lfont, nfont, x, y, w, h)
{ {
ostringstream info; ostringstream info;
info << describeCDFVersion(cart.myCDFSubtype) << " cartridge\n" info << describeCDFVersion(cart.myCDFSubtype) << " cartridge\n"
<< (cart.romSize() / 1024) << "K ROM\n" << (cart.romSize() / 1024) << "K ROM\n"
<< (cart.ramSize() / 1024) << "K RAM\n" << (cart.ramSize() / 1024) << "K RAM\n"
<< "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
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)

View File

@ -64,9 +64,24 @@ CartridgeCDFWidget::CartridgeCDFWidget(
"Fast Fetcher enabled"); "Fast Fetcher enabled");
myFastFetch->setTarget(this); myFastFetch->setTarget(this);
myFastFetch->setEditable(false); myFastFetch->setEditable(false);
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();
@ -219,6 +235,10 @@ void CartridgeCDFWidget::saveOldState()
myOldState.mwavesizes.clear(); myOldState.mwavesizes.clear();
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)
{ {
@ -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,18 +277,29 @@ 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
IntArray alist; IntArray alist;
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};

File diff suppressed because it is too large Load Diff

View File

@ -1,372 +1,395 @@
//============================================================================ //============================================================================
// //
// SSSS tt lll lll // SSSS tt lll lll
// SS SS tt ll ll // SS SS tt ll ll
// SS tttttt eeee ll ll aaaa // SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa // SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa // SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa // SSSS ttt eeeee llll llll aaaaa
// //
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony // Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// and the Stella Team // and the Stella Team
// //
// See the file "License.txt" for information on usage and redistribution of // See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES. // this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================ //============================================================================
#ifndef CARTRIDGE_CDF_HXX #ifndef CARTRIDGE_CDF_HXX
#define CARTRIDGE_CDF_HXX #define CARTRIDGE_CDF_HXX
class System; class System;
#include "bspf.hxx" #include "bspf.hxx"
#include "CartARM.hxx" #include "CartARM.hxx"
/** /**
Cartridge class used for CDF/CDFJ/CDFJ+. Cartridge class used for CDF/CDFJ/CDFJ+.
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
2 fast jump queues 2 fast jump queues
1 parameter queue 1 parameter queue
3 channel digital audio/1 channel sampled sound 3 channel digital audio/1 channel sampled sound
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)
Bankswitching Note: 2) 64/128/256/512K ROM and16/32K RAM - compatible with 64-Pin LPC213X Family
CDF/CDFJ uses $FFF5 through $FFFB (initial bank 6)
CDFJ+ uses $FFF4 through $FFFA (initial bank 0) 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
The letters CDFJ stand for Chris, Darrell, Fred, and John. 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.
@authors: Darrell Spice Jr, Chris Walton, Fred Quimby, John Champeau
Thomas Jentzsch, Stephen Anthony, Bradford W. Mott Bankswitching Note:
*/ CDF/CDFJ uses $FFF5 through $FFFB (initial bank 6)
class CartridgeCDF : public CartridgeARM CDFJ+ uses $FFF4 through $FFFA (initial bank 0)
{
friend class CartridgeCDFWidget; The letters CDFJ stand for Chris, Darrell, Fred, and John.
friend class CartridgeCDFInfoWidget;
friend class CartridgeRamCDFWidget; @authors: Darrell Spice Jr, Chris Walton, Fred Quimby, John Champeau
Thomas Jentzsch, Stephen Anthony, Bradford W. Mott
public: */
class CartridgeCDF : public CartridgeARM
enum class CDFSubtype { {
CDF0, friend class CartridgeCDFWidget;
CDF1, friend class CartridgeCDFInfoWidget;
CDFJ, friend class CartridgeRamCDFWidget;
CDFJplus
}; public:
public: enum class CDFSubtype {
/** CDF0,
Create a new cartridge using the specified image CDF1,
CDFJ,
@param image Pointer to the ROM image CDFJplus
@param size The size of the ROM image };
@param md5 The md5sum of the ROM image
@param settings A reference to the various settings (read-only) public:
*/ /**
CartridgeCDF(const ByteBuffer& image, size_t size, const string& md5, Create a new cartridge using the specified image
const Settings& settings);
~CartridgeCDF() override = default; @param image Pointer to the ROM image
@param size The size of the ROM image
public: @param md5 The md5sum of the ROM image
/** @param settings A reference to the various settings (read-only)
Reset device to its power-on state */
*/ CartridgeCDF(const ByteBuffer& image, size_t size, const string& md5,
void reset() override; const Settings& settings);
~CartridgeCDF() override = default;
/**
Install cartridge in the specified system. Invoked by the system public:
when the cartridge is attached to it. /**
Reset device to its power-on state
@param system The system the device should install itself in */
*/ void reset() override;
void install(System& system) override;
/**
/** Install cartridge in the specified system. Invoked by the system
Install pages for the specified bank in the system. when the cartridge is attached to it.
@param bank The bank that should be installed in the system @param system The system the device should install itself in
@param segment The segment the bank should be using */
void install(System& system) override;
@return true, if bank has changed
*/ /**
bool bank(uInt16 bank, uInt16 segment = 0) override; Install pages for the specified bank in the system.
/** @param bank The bank that should be installed in the system
Get the current bank. @param segment The segment the bank should be using
@param address The address to use when querying the bank @return true, if bank has changed
*/ */
uInt16 getBank(uInt16 address = 0) const override; bool bank(uInt16 bank, uInt16 segment = 0) override;
/** /**
Query the number of banks supported by the cartridge. Get the current bank.
*/
uInt16 romBankCount() const override; @param address The address to use when querying the bank
*/
/** uInt16 getBank(uInt16 address = 0) const override;
Patch the cartridge ROM.
/**
@param address The ROM address to patch Query the number of banks supported by the cartridge.
@param value The value to place into the address */
@return Success or failure of the patch operation uInt16 romBankCount() const override;
*/
bool patch(uInt16 address, uInt8 value) override; /**
Patch the cartridge ROM.
/**
Access the internal ROM image for this cartridge. @param address The ROM address to patch
@param value The value to place into the address
@param size Set to the size of the internal ROM image data @return Success or failure of the patch operation
@return A reference to the internal ROM image data */
*/ bool patch(uInt16 address, uInt8 value) override;
const ByteBuffer& getImage(size_t& size) const override;
/**
/** Access the internal ROM image for this cartridge.
Save the current state of this cart to the given Serializer.
@param size Set to the size of the internal ROM image data
@param out The Serializer object to use @return A reference to the internal ROM image data
@return False on any errors, else true */
*/ const ByteBuffer& getImage(size_t& size) const override;
bool save(Serializer& out) const override;
/**
/** Save the current state of this cart to the given Serializer.
Load the current state of this cart from the given Serializer.
@param out The Serializer object to use
@param in The Serializer object to use @return False on any errors, else true
@return False on any errors, else true */
*/ bool save(Serializer& out) const override;
bool load(Serializer& in) override;
/**
/** Load the current state of this cart from the given Serializer.
Get a descriptor for the device name (used in error checking).
@param in The Serializer object to use
@return The name of the object @return False on any errors, else true
*/ */
string name() const override; bool load(Serializer& in) override;
/** /**
Used for Thumbulator to pass values back to the cartridge Get a descriptor for the device name (used in error checking).
*/
uInt32 thumbCallback(uInt8 function, uInt32 value1, uInt32 value2) override; @return The name of the object
*/
/** string name() const override;
Query the internal RAM size of the cart.
/**
@return The internal RAM size Used for Thumbulator to pass values back to the cartridge
*/ */
uInt32 internalRamSize() const override { return uInt32(myRAM.size()); } uInt32 thumbCallback(uInt8 function, uInt32 value1, uInt32 value2) override;
/** /**
Read a byte from cart internal RAM. Query the internal RAM size of the cart.
@return The value of the interal RAM byte @return The internal RAM size
*/ */
uInt8 internalRamGetValue(uInt16 addr) const override; uInt32 internalRamSize() const override { return uInt32(myRAM.size()); }
/** /**
Set if we are using CDFJ+ bankswitching Read a byte from cart internal RAM.
*/
bool isCDFJplus() const; @return The value of the interal RAM byte
*/
/** uInt8 internalRamGetValue(uInt16 addr) const override;
Size of SRAM (RAM) area in cart
*/ /**
uInt32 ramSize() const; Set if we are using CDFJ+ bankswitching
*/
/** bool isCDFJplus() const;
Size of Flash memory (ROM) area in cart
*/ /**
uInt32 romSize() const; Size of SRAM (RAM) area in cart
*/
#ifdef DEBUGGER_SUPPORT uInt32 ramSize() const;
/**
Get debugger widget responsible for accessing the inner workings /**
of the cart. Size of Flash memory (ROM) area in cart
*/ */
CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, uInt32 romSize() const;
const GUI::Font& nfont, int x, int y, int w, int h) override;
CartDebugWidget* infoWidget(GuiObject* boss, const GUI::Font& lfont, #ifdef DEBUGGER_SUPPORT
const GUI::Font& nfont, int x, int y, int w, int h) override; /**
#endif Get debugger widget responsible for accessing the inner workings
of the cart.
public: */
/** CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont,
Get the byte at the specified address. const GUI::Font& nfont, int x, int y, int w, int h) override;
CartDebugWidget* infoWidget(GuiObject* boss, const GUI::Font& lfont,
@return The byte at the specified address const GUI::Font& nfont, int x, int y, int w, int h) override;
*/ #endif
uInt8 peek(uInt16 address) override;
public:
/** /**
Change the byte at the specified address to the given value Get the byte at the specified address.
@param address The address where the value should be stored @return The byte at the specified address
@param value The value to be stored at the address */
@return True if the poke changed the device address space, else false uInt8 peek(uInt16 address) override;
*/
bool poke(uInt16 address, uInt8 value) override; /**
Change the byte at the specified address to the given value
private:
/** @param address The address where the value should be stored
Checks if startup bank randomization is enabled. For this scheme, @param value The value to be stored at the address
randomization is not supported, since the ARM code is always in a @return True if the poke changed the device address space, else false
pre-defined bank, and we *must* start from there. */
*/ bool poke(uInt16 address, uInt8 value) override;
bool randomStartBank() const override { return false; }
private:
/** /**
Sets the initial state of the DPC pointers and RAM Checks if startup bank randomization is enabled. For this scheme,
*/ randomization is not supported, since the ARM code is always in a
void setInitialState() override; pre-defined bank, and we *must* start from there.
*/
/** bool randomStartBank() const override { return false; }
Updates any data fetchers in music mode based on the number of
CPU cycles which have passed since the last update. /**
*/ Sets the initial state of the DPC pointers and RAM
void updateMusicModeDataFetchers(); */
void setInitialState() override;
/**
Call Special Functions /**
*/ Updates any data fetchers in music mode based on the number of
void callFunction(uInt8 value); CPU cycles which have passed since the last update.
*/
uInt32 getDatastreamPointer(uInt8 index) const; void updateMusicModeDataFetchers();
void setDatastreamPointer(uInt8 index, uInt32 value);
/**
uInt32 getDatastreamIncrement(uInt8 index) const; Call Special Functions
*/
uInt8 readFromDatastream(uInt8 index); void callFunction(uInt8 value);
uInt32 getWaveform(uInt8 index) const; uInt32 getDatastreamPointer(uInt8 index) const;
uInt32 getWaveformSize(uInt8 index) const; void setDatastreamPointer(uInt8 index, uInt32 value);
uInt32 getSample();
void setupVersion(); uInt32 getDatastreamIncrement(uInt8 index) const;
/** uInt8 readFromDatastream(uInt8 index);
Answer whether this is a PlusROM cart. Note that until the
initialize method has been called, this will always return false. uInt32 getWaveform(uInt8 index) const;
uInt32 getWaveformSize(uInt8 index) const;
@return Whether this is actually a PlusROM cart uInt32 getSample();
*/ void setupVersion();
bool isPlusROM() const override { return myPlusROM->isValid(); }
uInt32 scanCDFDriver(uInt32 value);
private:
// The ROM image of the cartridge /**
ByteBuffer myImage{nullptr}; Answer whether this is a PlusROM cart. Note that until the
initialize method has been called, this will always return false.
// The size of the ROM image
size_t mySize{0}; @return Whether this is actually a PlusROM cart
*/
// Pointer to the program ROM image of the cartridge bool isPlusROM() const override { return myPlusROM->isValid(); }
uInt8* myProgramImage{nullptr};
private:
// Pointer to the display ROM image of the cartridge // The ROM image of the cartridge
uInt8* myDisplayImage{nullptr}; ByteBuffer myImage{nullptr};
// Pointer to the driver image in RAM // The size of the ROM image
uInt8* myDriverImage{nullptr}; size_t mySize{0};
// The CDFJ 8K RAM image, used as: // Pointer to the program ROM image of the cartridge
// $0000 - 2K Driver uInt8* myProgramImage{nullptr};
// $0800 - 4K Display Data
// $1800 - 2K C Variable & Stack // Pointer to the display ROM image of the cartridge
// For CDFJ+, used as: uInt8* myDisplayImage{nullptr};
// $0000 - 2K Driver
// $0800 - Display Data, C Variables & Stack // Pointer to the driver image in RAM
std::array<uInt8, 32_KB> myRAM; uInt8* myDriverImage{nullptr};
// Indicates the offset into the ROM image (aligns to current bank) // The CDFJ 8K RAM image, used as:
uInt16 myBankOffset{0}; // $0000 - 2K Driver
// $0800 - 4K Display Data
// System cycle count from when the last update to music data fetchers occurred // $1800 - 2K C Variable & Stack
uInt64 myAudioCycles{0}; // For CDFJ+, used as:
// $0000 - 2K Driver
// ARM cycle count from when the last callFunction() occurred // $0800 - Display Data, C Variables & Stack
uInt64 myARMCycles{0}; std::array<uInt8, 32_KB> myRAM;
// The audio routines in the driver run in 32-bit mode and take advantage // Indicates the offset into the ROM image (aligns to current bank)
// of the FIQ Shadow Registers which are not accessible to 16-bit thumb uInt16 myBankOffset{0};
// code. As such, Thumbulator does not support them. The driver supplies a
// few 16-bit subroutines used to pass values from 16-bit to 32-bit. The // System cycle count from when the last update to music data fetchers occurred
// Thumbulator will trap these calls and pass the appropriate information to uInt64 myAudioCycles{0};
// the Cartridge Class via callFunction() so it can emulate the 32 bit audio routines.
// ARM cycle count from when the last callFunction() occurred
/* Register usage for audio: uInt64 myARMCycles{0};
r8 = channel0 accumulator
r9 = channel1 accumulator // The audio routines in the driver run in 32-bit mode and take advantage
r10 = channel2 accumulator // of the FIQ Shadow Registers which are not accessible to 16-bit thumb
r11 = channel0 frequency // code. As such, Thumbulator does not support them. The driver supplies a
r12 = channel1 frequency // few 16-bit subroutines used to pass values from 16-bit to 32-bit. The
r13 = channel2 frequency // Thumbulator will trap these calls and pass the appropriate information to
r14 = timer base */ // the Cartridge Class via callFunction() so it can emulate the 32 bit audio routines.
// The music counters, ARM FIQ shadow registers r8, r9, r10 /* Register usage for audio:
std::array<uInt32, 3> myMusicCounters{0}; r8 = channel0 accumulator
r9 = channel1 accumulator
// The music frequency, ARM FIQ shadow registers r11, r12, r13 r10 = channel2 accumulator
std::array<uInt32, 3> myMusicFrequencies{0}; r11 = channel0 frequency
r12 = channel1 frequency
// The music waveform sizes r13 = channel2 frequency
std::array<uInt8, 3> myMusicWaveformSize{0}; r14 = timer base */
// Fractional CDF music, OSC clocks unused during the last update // The music counters, ARM FIQ shadow registers r8, r9, r10
double myFractionalClocks{0.0}; std::array<uInt32, 3> myMusicCounters{0};
// Controls mode, lower nybble sets Fast Fetch, upper nybble sets audio // The music frequency, ARM FIQ shadow registers r11, r12, r13
// -0 = Fast Fetch ON std::array<uInt32, 3> myMusicFrequencies{0};
// -F = Fast Fetch OFF
// 0- = Packed Digital Sample // The music waveform sizes
// F- = 3 Voice Music std::array<uInt8, 3> myMusicWaveformSize{0};
uInt8 myMode{0xFF};
// Fractional CDF music, OSC clocks unused during the last update
// set to address of #value if last byte peeked was A9 (LDA #) double myFractionalClocks{0.0};
uInt16 myLDAimmediateOperandAddress{0};
// Controls mode, lower nybble sets Fast Fetch, upper nybble sets audio
// set to address of the JMP operand if last byte peeked was 4C // -0 = Fast Fetch ON
// *and* the next two bytes in ROM are 00 00 // -F = Fast Fetch OFF
uInt16 myJMPoperandAddress{0}; // 0- = Packed Digital Sample
// F- = 3 Voice Music
uInt8 myFastJumpActive{0}; uInt8 myMode{0xFF};
// Pointer to the array of datastream pointers // set to address of #value if last byte peeked was A9 (LDA #),
uInt16 myDatastreamBase{0}; // or for CDFJ+ variations if A0 (LDY #) or A2 (LDX #)
uInt16 myLDAXYimmediateOperandAddress{0};
// Pointer to the array of datastream increments
uInt16 myDatastreamIncrementBase{0}; // Some CDFJ+ drivers also override LDX # and/or LDY # for fast fetcher
// use. These flag if this has been done.
// Pointer to the beginning of the waveform data block bool myLDXenabled{false};
uInt16 myWaveformBase{0}; bool myLDYenabled{false};
// Amplitude stream index // Some CDFJ+ drivers allow setting a fetcher base offset to allow
uInt8 myAmplitudeStream{0}; // immediate load of specific ranges. This is the location within the RAM
// copy of the CDFJ+ driver of the offset.
// Mask for determining the index of the datastream during fastjump // ex. if 16, immedate lda #>=16 <=51 will trigger a FASTFETCH
uInt8 myFastjumpStreamIndexMask{0}; // default is 0 so lda #>=0 <=35 will trigger a FASTFETCH
//
// The currently selected fastjump stream uInt16 myFastFetcherOffset{0};
uInt8 myFastJumpStream{0};
// set to address of the JMP operand if last byte peeked was 4C
// CDF subtype // *and* the next two bytes in ROM are 00 00
CDFSubtype myCDFSubtype{CDFSubtype::CDF0}; uInt16 myJMPoperandAddress{0};
private: uInt8 myFastJumpActive{0};
// Following constructors and assignment operators not supported
CartridgeCDF() = delete; // Pointer to the array of datastream pointers
CartridgeCDF(const CartridgeCDF&) = delete; uInt16 myDatastreamBase{0};
CartridgeCDF(CartridgeCDF&&) = delete;
CartridgeCDF& operator=(const CartridgeCDF&) = delete; // Pointer to the array of datastream increments
CartridgeCDF& operator=(CartridgeCDF&&) = delete; uInt16 myDatastreamIncrementBase{0};
};
// Pointer to the beginning of the waveform data block
#endif uInt16 myWaveformBase{0};
// Amplitude stream index
uInt8 myAmplitudeStream{0};
// Mask for determining the index of the datastream during fastjump
uInt8 myFastjumpStreamIndexMask{0};
// The currently selected fastjump stream
uInt8 myFastJumpStream{0};
// CDF subtype
CDFSubtype myCDFSubtype{CDFSubtype::CDF0};
private:
// Following constructors and assignment operators not supported
CartridgeCDF() = delete;
CartridgeCDF(const CartridgeCDF&) = delete;
CartridgeCDF(CartridgeCDF&&) = delete;
CartridgeCDF& operator=(const CartridgeCDF&) = delete;
CartridgeCDF& operator=(CartridgeCDF&&) = delete;
};
#endif