mirror of https://github.com/stella-emu/stella.git
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:
parent
313b6c6c98
commit
7b026e6ad1
|
@ -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)
|
||||||
|
|
|
@ -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]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue