mirror of https://github.com/stella-emu/stella.git
Merge pull request #110 from SpiceWare/master
Preliminary support for BUS and CDF
This commit is contained in:
commit
7c6821dfcb
|
@ -74,6 +74,12 @@ string Base::toString(int value, Common::Base::Format outputBase)
|
|||
case Base::F_16_2: // base 16: 2 bytes wide
|
||||
std::snprintf(vToS_buf, 3, myFmt[1], value);
|
||||
break;
|
||||
case Base::F_16_2_2:
|
||||
std::snprintf(vToS_buf, 6, "%02X.%02X", value >> 8, value & 0xff );
|
||||
break;
|
||||
case Base::F_16_3_2:
|
||||
std::snprintf(vToS_buf, 7, "%03X.%02X", value >> 8, value & 0xff );
|
||||
break;
|
||||
case Base::F_16_4: // base 16: 4 bytes wide
|
||||
std::snprintf(vToS_buf, 5, myFmt[2], value);
|
||||
break;
|
||||
|
|
|
@ -42,6 +42,8 @@ class Base
|
|||
F_16, // base 16: 2, 4, 8 bytes (depending on value)
|
||||
F_16_1, // base 16: 1 byte wide
|
||||
F_16_2, // base 16: 2 bytes wide
|
||||
F_16_2_2, // base 16: fractional value shown as xx.xx
|
||||
F_16_3_2, // base 16: fractional value shown as xxx.xx
|
||||
F_16_4, // base 16: 4 bytes wide
|
||||
F_16_8, // base 16: 8 bytes wide
|
||||
F_10, // base 10: 3 or 5 bytes (depending on value)
|
||||
|
|
|
@ -0,0 +1,373 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2015 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: CartBUSWidget.cxx 3131 2015-01-01 03:49:32Z stephena $
|
||||
//============================================================================
|
||||
|
||||
#include "CartBUS.hxx"
|
||||
#include "DataGridWidget.hxx"
|
||||
#include "PopUpWidget.hxx"
|
||||
#include "CartBUSWidget.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeBUSWidget::CartridgeBUSWidget(
|
||||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h, CartridgeBUS& cart)
|
||||
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
||||
myCart(cart)
|
||||
{
|
||||
uInt16 size = 8 * 4096;
|
||||
|
||||
ostringstream info;
|
||||
info << "BUS Stuffing cartridge\n"
|
||||
<< "32K ROM, seven 4K banks are accessible to 2600\n"
|
||||
<< "8K BUS RAM\n"
|
||||
<< "BUS registers accessible @ $F000 - $F03F\n"
|
||||
<< "Banks accessible at hotspots $FF5 to $FFB\n"
|
||||
<< "Startup bank = " << cart.myStartBank << "\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)
|
||||
{
|
||||
uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset];
|
||||
start -= start % 0x1000;
|
||||
info << "Bank " << i << " @ $" << HEX4 << (start + 0x80) << " - "
|
||||
<< "$" << (start + 0xFFF) << " (hotspot = $" << (spot+i) << ")\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
int xpos = 10,
|
||||
ypos = addBaseInformation(size, "AtariAge", info.str()) +
|
||||
myLineHeight;
|
||||
|
||||
VariantList items;
|
||||
VarList::push_back(items, "0 ($FF5)");
|
||||
VarList::push_back(items, "1 ($FF6)");
|
||||
VarList::push_back(items, "2 ($FF7)");
|
||||
VarList::push_back(items, "3 ($FF8)");
|
||||
VarList::push_back(items, "4 ($FF9)");
|
||||
VarList::push_back(items, "5 ($FFA)");
|
||||
VarList::push_back(items, "6 ($FFB)");
|
||||
myBank =
|
||||
new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFx) "),
|
||||
myLineHeight, items, "Set bank: ",
|
||||
_font.getStringWidth("Set bank: "), kBankChanged);
|
||||
myBank->setTarget(this);
|
||||
addFocusWidget(myBank);
|
||||
|
||||
int lwidth = _font.getStringWidth("Datastream Increments: "); // get width of the widest label
|
||||
|
||||
// Datastream Pointers
|
||||
xpos = 0; ypos += myLineHeight + 4;
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
||||
myFontHeight, "Datastream Pointers: ", kTextAlignLeft);
|
||||
xpos += lwidth;
|
||||
|
||||
myDatastreamPointers = new DataGridWidget(boss, _nfont, 0, ypos+myLineHeight-2, 4, 4, 6, 32, Common::Base::F_16_3_2);
|
||||
myDatastreamPointers->setTarget(this);
|
||||
myDatastreamPointers->setEditable(false);
|
||||
|
||||
// Datastream Increments
|
||||
xpos = 0 + myDatastreamPointers->getWidth();
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
||||
myFontHeight, "Datastream Increments: ", kTextAlignLeft);
|
||||
|
||||
myDatastreamIncrements = new DataGridWidget(boss, _nfont, xpos, ypos+myLineHeight-2, 4, 4, 5, 32, Common::Base::F_16_2_2);
|
||||
myDatastreamIncrements->setTarget(this);
|
||||
myDatastreamIncrements->setEditable(false);
|
||||
|
||||
// Datastream Maps
|
||||
xpos = 0; ypos += myLineHeight*5 + 4;
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
||||
myFontHeight, "Address Maps: ", kTextAlignLeft);
|
||||
|
||||
myAddressMaps = new DataGridWidget(boss, _nfont, 0, ypos+myLineHeight-2, 8, 5, 8, 32, Common::Base::F_16_8);
|
||||
myAddressMaps->setTarget(this);
|
||||
myAddressMaps->setEditable(false);
|
||||
|
||||
// Music counters
|
||||
xpos = 10; ypos += myLineHeight*6 + 4;
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
||||
myFontHeight, "Music Counters: ", kTextAlignLeft);
|
||||
xpos += lwidth;
|
||||
|
||||
myMusicCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::F_16_8);
|
||||
myMusicCounters->setTarget(this);
|
||||
myMusicCounters->setEditable(false);
|
||||
|
||||
// Music frequencies
|
||||
xpos = 10; ypos += myLineHeight + 4;
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
||||
myFontHeight, "Music Frequencies: ", kTextAlignLeft);
|
||||
xpos += lwidth;
|
||||
|
||||
myMusicFrequencies = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::F_16_8);
|
||||
myMusicFrequencies->setTarget(this);
|
||||
myMusicFrequencies->setEditable(false);
|
||||
|
||||
// Music waveforms
|
||||
xpos = 10; ypos += myLineHeight + 4;
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
||||
myFontHeight, "Music Waveforms: ", kTextAlignLeft);
|
||||
xpos += lwidth;
|
||||
|
||||
myMusicWaveforms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 4, 16, Common::Base::F_16_2);
|
||||
myMusicWaveforms->setTarget(this);
|
||||
myMusicWaveforms->setEditable(false);
|
||||
|
||||
// Music waveform sizes
|
||||
xpos = 10; ypos += myLineHeight + 4;
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
||||
myFontHeight, "Music Waveform Sizes: ", kTextAlignLeft);
|
||||
xpos += lwidth;
|
||||
|
||||
myMusicWaveformSizes = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 4, 16, Common::Base::F_16_2);
|
||||
myMusicWaveformSizes->setTarget(this);
|
||||
myMusicWaveformSizes->setEditable(false);
|
||||
|
||||
|
||||
// BUS stuff and ZP STY flags
|
||||
xpos = 10; ypos += myLineHeight + 4;
|
||||
myBusOverdrive = new CheckboxWidget(boss, _font, xpos, ypos, "BUS Overdrive enabled");
|
||||
myBusOverdrive->setTarget(this);
|
||||
myBusOverdrive->setEditable(false);
|
||||
xpos = _font.getStringWidth("CHECKBOX BUS Overdrive enabled");
|
||||
myZPSTY = new CheckboxWidget(boss, _font, xpos, ypos, "Zero Page STY");
|
||||
myZPSTY->setTarget(this);
|
||||
myZPSTY->setEditable(false);
|
||||
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeBUSWidget::saveOldState()
|
||||
{
|
||||
myOldState.tops.clear();
|
||||
myOldState.bottoms.clear();
|
||||
myOldState.datastreampointers.clear();
|
||||
myOldState.datastreamincrements.clear();
|
||||
myOldState.addressmaps.clear();
|
||||
myOldState.mcounters.clear();
|
||||
myOldState.mfreqs.clear();
|
||||
myOldState.mwaves.clear();
|
||||
myOldState.mwavesizes.clear();
|
||||
myOldState.internalram.clear();
|
||||
|
||||
for(uInt32 i = 0; i < 16; i++)
|
||||
{
|
||||
// Pointers are stored as:
|
||||
// PPPFF---
|
||||
//
|
||||
// Increments are stored as
|
||||
// ----IIFF
|
||||
//
|
||||
// P = Pointer
|
||||
// I = Increment
|
||||
// F = Fractional
|
||||
|
||||
myOldState.datastreampointers.push_back(myCart.getDatastreamPointer(i)>>12);
|
||||
myOldState.datastreamincrements.push_back(myCart.getDatastreamIncrement(i));
|
||||
}
|
||||
|
||||
for(uInt32 i = 0; i < 40; i++)
|
||||
{
|
||||
myOldState.addressmaps.push_back(myCart.getAddressMap(i));
|
||||
}
|
||||
|
||||
for(uInt32 i = 0; i < 3; ++i)
|
||||
{
|
||||
myOldState.mcounters.push_back(myCart.myMusicCounters[i]);
|
||||
}
|
||||
|
||||
for(uInt32 i = 0; i < 3; ++i)
|
||||
{
|
||||
myOldState.mfreqs.push_back(myCart.myMusicFrequencies[i]);
|
||||
myOldState.mwaves.push_back(myCart.getWaveform(i) >> 5);
|
||||
myOldState.mwavesizes.push_back(myCart.getWaveformSize((i)));
|
||||
}
|
||||
|
||||
for(uInt32 i = 0; i < internalRamSize(); ++i)
|
||||
myOldState.internalram.push_back(myCart.myBUSRAM[i]);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeBUSWidget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
|
||||
// Get registers, using change tracking
|
||||
IntArray alist;
|
||||
IntArray vlist;
|
||||
BoolArray changed;
|
||||
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
for(int i = 0; i < 16; ++i)
|
||||
{
|
||||
// Pointers are stored as:
|
||||
// PPPFF---
|
||||
//
|
||||
// Increments are stored as
|
||||
// ----IIFF
|
||||
//
|
||||
// P = Pointer
|
||||
// I = Increment
|
||||
// F = Fractional
|
||||
|
||||
uInt32 pointervalue = myCart.getDatastreamPointer(i) >> 12;
|
||||
alist.push_back(0); vlist.push_back(pointervalue);
|
||||
changed.push_back(pointervalue != myOldState.datastreampointers[i]);
|
||||
}
|
||||
myDatastreamPointers->setList(alist, vlist, changed);
|
||||
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
for(int i = 0; i < 16; ++i)
|
||||
{
|
||||
uInt32 incrementvalue = myCart.getDatastreamIncrement(i);
|
||||
alist.push_back(0); vlist.push_back(incrementvalue);
|
||||
changed.push_back(incrementvalue != myOldState.datastreamincrements[i]);
|
||||
}
|
||||
myDatastreamIncrements->setList(alist, vlist, changed);
|
||||
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
for(int i = 0; i < 40; ++i)
|
||||
{
|
||||
uInt32 mapvalue = myCart.getAddressMap(i);
|
||||
alist.push_back(0); vlist.push_back(mapvalue);
|
||||
changed.push_back(mapvalue != myOldState.addressmaps[i]);
|
||||
}
|
||||
myAddressMaps->setList(alist, vlist, changed);
|
||||
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
alist.push_back(0); vlist.push_back(myCart.myMusicCounters[i]);
|
||||
changed.push_back(myCart.myMusicCounters[i] != (uInt32)myOldState.mcounters[i]);
|
||||
}
|
||||
myMusicCounters->setList(alist, vlist, changed);
|
||||
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
alist.push_back(0); vlist.push_back(myCart.myMusicFrequencies[i]);
|
||||
changed.push_back(myCart.myMusicFrequencies[i] != (uInt32)myOldState.mfreqs[i]);
|
||||
}
|
||||
myMusicFrequencies->setList(alist, vlist, changed);
|
||||
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
alist.push_back(0); vlist.push_back(myCart.getWaveform(i) >> 5);
|
||||
changed.push_back((myCart.getWaveform(i) >> 5) != myOldState.mwaves[i]);
|
||||
}
|
||||
myMusicWaveforms->setList(alist, vlist, changed);
|
||||
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
alist.push_back(0); vlist.push_back(myCart.getWaveformSize(i));
|
||||
changed.push_back((myCart.getWaveformSize(i)) != myOldState.mwavesizes[i]);
|
||||
}
|
||||
myMusicWaveformSizes->setList(alist, vlist, changed);
|
||||
|
||||
myBusOverdrive->setState(myCart.getBusStuffFlag());
|
||||
myZPSTY->setState(myCart.mySTYZeroPage);
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeBUSWidget::handleCommand(CommandSender* sender,
|
||||
int cmd, int data, int id)
|
||||
{
|
||||
if(cmd == kBankChanged)
|
||||
{
|
||||
myCart.unlockBank();
|
||||
myCart.bank(myBank->getSelected());
|
||||
myCart.lockBank();
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string CartridgeBUSWidget::bankState()
|
||||
{
|
||||
ostringstream& buf = buffer();
|
||||
|
||||
static const char* spot[] = {
|
||||
"$FF5", "$FF6", "$FF7", "$FF8", "$FF9", "$FFA", "$FFB"
|
||||
};
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 CartridgeBUSWidget::internalRamSize()
|
||||
{
|
||||
return 8*1024;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 CartridgeBUSWidget::internalRamRPort(int start)
|
||||
{
|
||||
return 0x0000 + start;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string CartridgeBUSWidget::internalRamDescription()
|
||||
{
|
||||
ostringstream desc;
|
||||
desc << "$0000 - $07FF - BUS driver\n"
|
||||
<< " not accessible to 6507\n"
|
||||
<< "$0800 - $17FF - 4K Data Stream storage\n"
|
||||
<< " indirectly accessible to 6507\n"
|
||||
<< " via BUS's Data Stream registers\n"
|
||||
<< "$1800 - $1FFF - 2K C variable storage and stack\n"
|
||||
<< " not accessible to 6507";
|
||||
|
||||
return desc.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const ByteArray& CartridgeBUSWidget::internalRamOld(int start, int count)
|
||||
{
|
||||
myRamOld.clear();
|
||||
for(int i = 0; i < count; i++)
|
||||
myRamOld.push_back(myOldState.internalram[start + i]);
|
||||
return myRamOld;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const ByteArray& CartridgeBUSWidget::internalRamCurrent(int start, int count)
|
||||
{
|
||||
myRamCurrent.clear();
|
||||
for(int i = 0; i < count; i++)
|
||||
myRamCurrent.push_back(myCart.myBUSRAM[start + i]);
|
||||
return myRamCurrent;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeBUSWidget::internalRamSetValue(int addr, uInt8 value)
|
||||
{
|
||||
myCart.myBUSRAM[addr] = value;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 CartridgeBUSWidget::internalRamGetValue(int addr)
|
||||
{
|
||||
return myCart.myBUSRAM[addr];
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2015 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: CartBUSWidget.hxx 3131 2015-01-01 03:49:32Z stephena $
|
||||
//============================================================================
|
||||
|
||||
#ifndef CARTRIDGEBUS_WIDGET_HXX
|
||||
#define CARTRIDGEBUS_WIDGET_HXX
|
||||
|
||||
class CartridgeBUS;
|
||||
class PopUpWidget;
|
||||
class CheckboxWidget;
|
||||
class DataGridWidget;
|
||||
|
||||
#include "CartDebugWidget.hxx"
|
||||
|
||||
class CartridgeBUSWidget : public CartDebugWidget
|
||||
{
|
||||
public:
|
||||
CartridgeBUSWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
const GUI::Font& nfont,
|
||||
int x, int y, int w, int h,
|
||||
CartridgeBUS& cart);
|
||||
virtual ~CartridgeBUSWidget() { }
|
||||
|
||||
private:
|
||||
struct CartState {
|
||||
ByteArray tops;
|
||||
ByteArray bottoms;
|
||||
IntArray datastreampointers;
|
||||
IntArray datastreamincrements;
|
||||
IntArray addressmaps;
|
||||
IntArray mcounters;
|
||||
IntArray mfreqs;
|
||||
IntArray mwaves;
|
||||
IntArray mwavesizes;
|
||||
uInt32 random;
|
||||
ByteArray internalram;
|
||||
};
|
||||
|
||||
CartridgeBUS& myCart;
|
||||
PopUpWidget* myBank;
|
||||
|
||||
DataGridWidget* myDatastreamPointers;
|
||||
DataGridWidget* myDatastreamIncrements;
|
||||
DataGridWidget* myAddressMaps;
|
||||
DataGridWidget* myMusicCounters;
|
||||
DataGridWidget* myMusicFrequencies;
|
||||
DataGridWidget* myMusicWaveforms;
|
||||
DataGridWidget* myMusicWaveformSizes;
|
||||
CheckboxWidget* myBusOverdrive;
|
||||
CheckboxWidget* myZPSTY;
|
||||
CartState myOldState;
|
||||
|
||||
enum { kBankChanged = 'bkCH' };
|
||||
|
||||
private:
|
||||
void saveOldState() override;
|
||||
|
||||
void loadConfig() override;
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
|
||||
string bankState() override;
|
||||
|
||||
// start of functions for Cartridge RAM tab
|
||||
uInt32 internalRamSize() override;
|
||||
uInt32 internalRamRPort(int start) override;
|
||||
string internalRamDescription() override;
|
||||
const ByteArray& internalRamOld(int start, int count) override;
|
||||
const ByteArray& internalRamCurrent(int start, int count) override;
|
||||
void internalRamSetValue(int addr, uInt8 value) override;
|
||||
uInt8 internalRamGetValue(int addr) override;
|
||||
// end of functions for Cartridge RAM tab
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
CartridgeBUSWidget() = delete;
|
||||
CartridgeBUSWidget(const CartridgeBUSWidget&) = delete;
|
||||
CartridgeBUSWidget(CartridgeBUSWidget&&) = delete;
|
||||
CartridgeBUSWidget& operator=(const CartridgeBUSWidget&) = delete;
|
||||
CartridgeBUSWidget& operator=(CartridgeBUSWidget&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,350 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2015 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: CartCDFWidget.cxx 3131 2015-01-01 03:49:32Z stephena $
|
||||
//============================================================================
|
||||
|
||||
#include "CartCDF.hxx"
|
||||
#include "DataGridWidget.hxx"
|
||||
#include "PopUpWidget.hxx"
|
||||
#include "CartCDFWidget.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeCDFWidget::CartridgeCDFWidget(
|
||||
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
||||
int x, int y, int w, int h, CartridgeCDF& cart)
|
||||
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
||||
myCart(cart)
|
||||
{
|
||||
uInt16 size = 8 * 4096;
|
||||
|
||||
ostringstream info;
|
||||
info << "CDF Stuffing cartridge\n"
|
||||
<< "32K ROM, seven 4K banks are accessible to 2600\n"
|
||||
<< "8K CDF RAM\n"
|
||||
<< "CDF registers accessible @ $F000 - $F03F\n"
|
||||
<< "Banks accessible at hotspots $FF5 to $FFB\n"
|
||||
<< "Startup bank = " << cart.myStartBank << "\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)
|
||||
{
|
||||
uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset];
|
||||
start -= start % 0x1000;
|
||||
info << "Bank " << i << " @ $" << HEX4 << (start + 0x80) << " - "
|
||||
<< "$" << (start + 0xFFF) << " (hotspot = $" << (spot+i) << ")\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
int xpos = 10,
|
||||
ypos = addBaseInformation(size, "AtariAge", info.str()) +
|
||||
myLineHeight;
|
||||
|
||||
VariantList items;
|
||||
VarList::push_back(items, "0 ($FF5)");
|
||||
VarList::push_back(items, "1 ($FF6)");
|
||||
VarList::push_back(items, "2 ($FF7)");
|
||||
VarList::push_back(items, "3 ($FF8)");
|
||||
VarList::push_back(items, "4 ($FF9)");
|
||||
VarList::push_back(items, "5 ($FFA)");
|
||||
VarList::push_back(items, "6 ($FFB)");
|
||||
myBank =
|
||||
new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFx) "),
|
||||
myLineHeight, items, "Set bank: ",
|
||||
_font.getStringWidth("Set bank: "), kBankChanged);
|
||||
myBank->setTarget(this);
|
||||
addFocusWidget(myBank);
|
||||
|
||||
int lwidth = _font.getStringWidth("Datastream Increments: "); // get width of the widest label
|
||||
|
||||
// Datastream Pointers
|
||||
xpos = 0; ypos += myLineHeight + 4;
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
||||
myFontHeight, "Datastream Pointers: ", kTextAlignLeft);
|
||||
xpos += lwidth;
|
||||
|
||||
myDatastreamPointers = new DataGridWidget(boss, _nfont, 0, ypos+myLineHeight-2, 4, 8, 6, 32, Common::Base::F_16_3_2);
|
||||
myDatastreamPointers->setTarget(this);
|
||||
myDatastreamPointers->setEditable(false);
|
||||
|
||||
// Datastream Increments
|
||||
xpos = 0 + myDatastreamPointers->getWidth();
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
||||
myFontHeight, "Datastream Increments: ", kTextAlignLeft);
|
||||
|
||||
myDatastreamIncrements = new DataGridWidget(boss, _nfont, xpos, ypos+myLineHeight-2, 4, 8, 5, 32, Common::Base::F_16_2_2);
|
||||
myDatastreamIncrements->setTarget(this);
|
||||
myDatastreamIncrements->setEditable(false);
|
||||
|
||||
// Music counters
|
||||
xpos = 10; ypos += myLineHeight*10 + 4;
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
||||
myFontHeight, "Music Counters: ", kTextAlignLeft);
|
||||
xpos += lwidth;
|
||||
|
||||
myMusicCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::F_16_8);
|
||||
myMusicCounters->setTarget(this);
|
||||
myMusicCounters->setEditable(false);
|
||||
|
||||
// Music frequencies
|
||||
xpos = 10; ypos += myLineHeight + 4;
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
||||
myFontHeight, "Music Frequencies: ", kTextAlignLeft);
|
||||
xpos += lwidth;
|
||||
|
||||
myMusicFrequencies = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::F_16_8);
|
||||
myMusicFrequencies->setTarget(this);
|
||||
myMusicFrequencies->setEditable(false);
|
||||
|
||||
// Music waveforms
|
||||
xpos = 10; ypos += myLineHeight + 4;
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
||||
myFontHeight, "Music Waveforms: ", kTextAlignLeft);
|
||||
xpos += lwidth;
|
||||
|
||||
myMusicWaveforms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 4, 16, Common::Base::F_16_2);
|
||||
myMusicWaveforms->setTarget(this);
|
||||
myMusicWaveforms->setEditable(false);
|
||||
|
||||
// Music waveform sizes
|
||||
xpos = 10; ypos += myLineHeight + 4;
|
||||
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
||||
myFontHeight, "Music Waveform Sizes: ", kTextAlignLeft);
|
||||
xpos += lwidth;
|
||||
|
||||
myMusicWaveformSizes = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 4, 16, Common::Base::F_16_2);
|
||||
myMusicWaveformSizes->setTarget(this);
|
||||
myMusicWaveformSizes->setEditable(false);
|
||||
|
||||
// done differently than in DPC+, need to rethink debugger support
|
||||
// // Fast fetch and immediate mode LDA flags
|
||||
// xpos = 10; ypos += myLineHeight + 4;
|
||||
// myFastFetch = new CheckboxWidget(boss, _font, xpos, ypos, "Fast Fetcher enabled");
|
||||
// myFastFetch->setTarget(this);
|
||||
// myFastFetch->setEditable(false);
|
||||
// ypos += myLineHeight + 4;
|
||||
// myIMLDA = new CheckboxWidget(boss, _font, xpos, ypos, "Immediate mode LDA");
|
||||
// myIMLDA->setTarget(this);
|
||||
// myIMLDA->setEditable(false);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeCDFWidget::saveOldState()
|
||||
{
|
||||
myOldState.tops.clear();
|
||||
myOldState.bottoms.clear();
|
||||
myOldState.datastreampointers.clear();
|
||||
myOldState.datastreamincrements.clear();
|
||||
myOldState.addressmaps.clear();
|
||||
myOldState.mcounters.clear();
|
||||
myOldState.mfreqs.clear();
|
||||
myOldState.mwaves.clear();
|
||||
myOldState.mwavesizes.clear();
|
||||
myOldState.internalram.clear();
|
||||
|
||||
for(uInt32 i = 0; i < 32; i++)
|
||||
{
|
||||
// Pointers are stored as:
|
||||
// PPPFF---
|
||||
//
|
||||
// Increments are stored as
|
||||
// ----IIFF
|
||||
//
|
||||
// P = Pointer
|
||||
// I = Increment
|
||||
// F = Fractional
|
||||
|
||||
myOldState.datastreampointers.push_back(myCart.getDatastreamPointer(i)>>12);
|
||||
myOldState.datastreamincrements.push_back(myCart.getDatastreamIncrement(i));
|
||||
}
|
||||
|
||||
for(uInt32 i = 0; i < 3; ++i)
|
||||
{
|
||||
myOldState.mcounters.push_back(myCart.myMusicCounters[i]);
|
||||
}
|
||||
|
||||
for(uInt32 i = 0; i < 3; ++i)
|
||||
{
|
||||
myOldState.mfreqs.push_back(myCart.myMusicFrequencies[i]);
|
||||
myOldState.mwaves.push_back(myCart.getWaveform(i) >> 5);
|
||||
myOldState.mwavesizes.push_back(myCart.getWaveformSize((i)));
|
||||
}
|
||||
|
||||
for(uInt32 i = 0; i < internalRamSize(); ++i)
|
||||
myOldState.internalram.push_back(myCart.myCDFRAM[i]);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeCDFWidget::loadConfig()
|
||||
{
|
||||
myBank->setSelectedIndex(myCart.myCurrentBank);
|
||||
|
||||
// Get registers, using change tracking
|
||||
IntArray alist;
|
||||
IntArray vlist;
|
||||
BoolArray changed;
|
||||
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
for(int i = 0; i < 32; ++i)
|
||||
{
|
||||
// Pointers are stored as:
|
||||
// PPPFF---
|
||||
//
|
||||
// Increments are stored as
|
||||
// ----IIFF
|
||||
//
|
||||
// P = Pointer
|
||||
// I = Increment
|
||||
// F = Fractional
|
||||
|
||||
uInt32 pointervalue = myCart.getDatastreamPointer(i) >> 12;
|
||||
alist.push_back(0); vlist.push_back(pointervalue);
|
||||
changed.push_back(pointervalue != myOldState.datastreampointers[i]);
|
||||
}
|
||||
myDatastreamPointers->setList(alist, vlist, changed);
|
||||
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
for(int i = 0; i < 32; ++i)
|
||||
{
|
||||
uInt32 incrementvalue = myCart.getDatastreamIncrement(i);
|
||||
alist.push_back(0); vlist.push_back(incrementvalue);
|
||||
changed.push_back(incrementvalue != myOldState.datastreamincrements[i]);
|
||||
}
|
||||
myDatastreamIncrements->setList(alist, vlist, changed);
|
||||
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
alist.push_back(0); vlist.push_back(myCart.myMusicCounters[i]);
|
||||
changed.push_back(myCart.myMusicCounters[i] != (uInt32)myOldState.mcounters[i]);
|
||||
}
|
||||
myMusicCounters->setList(alist, vlist, changed);
|
||||
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
alist.push_back(0); vlist.push_back(myCart.myMusicFrequencies[i]);
|
||||
changed.push_back(myCart.myMusicFrequencies[i] != (uInt32)myOldState.mfreqs[i]);
|
||||
}
|
||||
myMusicFrequencies->setList(alist, vlist, changed);
|
||||
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
alist.push_back(0); vlist.push_back(myCart.getWaveform(i) >> 5);
|
||||
changed.push_back((myCart.getWaveform(i) >> 5) != myOldState.mwaves[i]);
|
||||
}
|
||||
myMusicWaveforms->setList(alist, vlist, changed);
|
||||
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
alist.push_back(0); vlist.push_back(myCart.getWaveformSize(i));
|
||||
changed.push_back((myCart.getWaveformSize(i)) != myOldState.mwavesizes[i]);
|
||||
}
|
||||
myMusicWaveformSizes->setList(alist, vlist, changed);
|
||||
|
||||
// done differently than in DPC+, need to rethink debugger support
|
||||
// myFastFetch->setState(myCart.myFastFetch);
|
||||
// myIMLDA->setState(myCart.myLDAimmediate);
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeCDFWidget::handleCommand(CommandSender* sender,
|
||||
int cmd, int data, int id)
|
||||
{
|
||||
if(cmd == kBankChanged)
|
||||
{
|
||||
myCart.unlockBank();
|
||||
myCart.bank(myBank->getSelected());
|
||||
myCart.lockBank();
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
string CartridgeCDFWidget::bankState()
|
||||
{
|
||||
ostringstream& buf = buffer();
|
||||
|
||||
static const char* spot[] = {
|
||||
"$FF5", "$FF6", "$FF7", "$FF8", "$FF9", "$FFA", "$FFB"
|
||||
};
|
||||
buf << "Bank = " << std::dec << myCart.myCurrentBank
|
||||
<< ", hotspot = " << spot[myCart.myCurrentBank];
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 CartridgeCDFWidget::internalRamSize()
|
||||
{
|
||||
return 8*1024;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt32 CartridgeCDFWidget::internalRamRPort(int start)
|
||||
{
|
||||
return 0x0000 + 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";
|
||||
|
||||
return desc.str();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const ByteArray& CartridgeCDFWidget::internalRamOld(int start, int count)
|
||||
{
|
||||
myRamOld.clear();
|
||||
for(int i = 0; i < count; i++)
|
||||
myRamOld.push_back(myOldState.internalram[start + i]);
|
||||
return myRamOld;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const ByteArray& CartridgeCDFWidget::internalRamCurrent(int start, int count)
|
||||
{
|
||||
myRamCurrent.clear();
|
||||
for(int i = 0; i < count; i++)
|
||||
myRamCurrent.push_back(myCart.myCDFRAM[start + i]);
|
||||
return myRamCurrent;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeCDFWidget::internalRamSetValue(int addr, uInt8 value)
|
||||
{
|
||||
myCart.myCDFRAM[addr] = value;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 CartridgeCDFWidget::internalRamGetValue(int addr)
|
||||
{
|
||||
return myCart.myCDFRAM[addr];
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2015 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: CartCDFWidget.hxx 3131 2015-01-01 03:49:32Z stephena $
|
||||
//============================================================================
|
||||
|
||||
#ifndef CARTRIDGECDF_WIDGET_HXX
|
||||
#define CARTRIDGECDF_WIDGET_HXX
|
||||
|
||||
class CartridgeCDF;
|
||||
class PopUpWidget;
|
||||
class CheckboxWidget;
|
||||
class DataGridWidget;
|
||||
|
||||
#include "CartDebugWidget.hxx"
|
||||
|
||||
class CartridgeCDFWidget : public CartDebugWidget
|
||||
{
|
||||
public:
|
||||
CartridgeCDFWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
const GUI::Font& nfont,
|
||||
int x, int y, int w, int h,
|
||||
CartridgeCDF& cart);
|
||||
virtual ~CartridgeCDFWidget() { }
|
||||
|
||||
private:
|
||||
struct CartState {
|
||||
ByteArray tops;
|
||||
ByteArray bottoms;
|
||||
IntArray datastreampointers;
|
||||
IntArray datastreamincrements;
|
||||
IntArray addressmaps;
|
||||
IntArray mcounters;
|
||||
IntArray mfreqs;
|
||||
IntArray mwaves;
|
||||
IntArray mwavesizes;
|
||||
uInt32 random;
|
||||
ByteArray internalram;
|
||||
};
|
||||
|
||||
CartridgeCDF& myCart;
|
||||
PopUpWidget* myBank;
|
||||
|
||||
DataGridWidget* myDatastreamPointers;
|
||||
DataGridWidget* myDatastreamIncrements;
|
||||
DataGridWidget* myMusicCounters;
|
||||
DataGridWidget* myMusicFrequencies;
|
||||
DataGridWidget* myMusicWaveforms;
|
||||
DataGridWidget* myMusicWaveformSizes;
|
||||
// done differently than in DPC+, need to rethink debugger support
|
||||
// CheckboxWidget* myFastFetch;
|
||||
// CheckboxWidget* myIMLDA;
|
||||
CartState myOldState;
|
||||
|
||||
enum { kBankChanged = 'bkCH' };
|
||||
|
||||
private:
|
||||
void saveOldState() override;
|
||||
|
||||
void loadConfig() override;
|
||||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
|
||||
string bankState() override;
|
||||
|
||||
// start of functions for Cartridge RAM tab
|
||||
uInt32 internalRamSize() override;
|
||||
uInt32 internalRamRPort(int start) override;
|
||||
string internalRamDescription() override;
|
||||
const ByteArray& internalRamOld(int start, int count) override;
|
||||
const ByteArray& internalRamCurrent(int start, int count) override;
|
||||
void internalRamSetValue(int addr, uInt8 value) override;
|
||||
uInt8 internalRamGetValue(int addr) override;
|
||||
// end of functions for Cartridge RAM tab
|
||||
|
||||
// Following constructors and assignment operators not supported
|
||||
CartridgeCDFWidget() = delete;
|
||||
CartridgeCDFWidget(const CartridgeCDFWidget&) = delete;
|
||||
CartridgeCDFWidget(CartridgeCDFWidget&&) = delete;
|
||||
CartridgeCDFWidget& operator=(const CartridgeCDFWidget&) = delete;
|
||||
CartridgeCDFWidget& operator=(CartridgeCDFWidget&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -26,6 +26,8 @@
|
|||
#include "Cart4K.hxx"
|
||||
#include "Cart4KSC.hxx"
|
||||
#include "CartAR.hxx"
|
||||
#include "CartBUS.hxx"
|
||||
#include "CartCDF.hxx"
|
||||
#include "CartCM.hxx"
|
||||
#include "CartCTY.hxx"
|
||||
#include "CartCV.hxx"
|
||||
|
@ -198,6 +200,10 @@ unique_ptr<Cartridge> Cartridge::create(const BytePtr& img, uInt32 size,
|
|||
cartridge = make_ptr<Cartridge4KSC>(image, size, settings);
|
||||
else if(type == "AR")
|
||||
cartridge = make_ptr<CartridgeAR>(image, size, settings);
|
||||
else if(type == "BUS")
|
||||
cartridge = make_ptr<CartridgeBUS>(image, size, settings);
|
||||
else if(type == "CDF")
|
||||
cartridge = make_ptr<CartridgeCDF>(image, size, settings);
|
||||
else if(type == "CM")
|
||||
cartridge = make_ptr<CartridgeCM>(image, size, settings);
|
||||
else if(type == "CTY")
|
||||
|
@ -472,6 +478,10 @@ string Cartridge::autodetectType(const uInt8* image, uInt32 size)
|
|||
type = "3E";
|
||||
else if(isProbably3F(image, size))
|
||||
type = "3F";
|
||||
else if (isProbablyBUS(image, size))
|
||||
type = "BUS";
|
||||
else if (isProbablyCDF(image, size))
|
||||
type = "CDF";
|
||||
else if(isProbablyDPCplus(image, size))
|
||||
type = "DPC+";
|
||||
else if(isProbablyCTY(image, size))
|
||||
|
@ -734,6 +744,8 @@ bool Cartridge::isProbablyDASH(const uInt8* image, uInt32 size)
|
|||
bool Cartridge::isProbablyDPCplus(const uInt8* image, uInt32 size)
|
||||
{
|
||||
// DPC+ ARM code has 2 occurrences of the string DPC+
|
||||
// Note: all Harmony/Melody custom drivers also contain the value
|
||||
// 0x10adab1e (LOADABLE) if needed for future improvement
|
||||
uInt8 signature[] = { 'D', 'P', 'C', '+' };
|
||||
return searchForBytes(image, size, signature, 4, 2);
|
||||
}
|
||||
|
@ -858,6 +870,26 @@ bool Cartridge::isProbablyBF(const uInt8* image, uInt32 size, const char*& type)
|
|||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Cartridge::isProbablyBUS(const uInt8* image, uInt32 size)
|
||||
{
|
||||
// BUS ARM code has 2 occurrences of the string BUS
|
||||
// Note: all Harmony/Melody custom drivers also contain the value
|
||||
// 0x10adab1e (LOADABLE) if needed for future improvement
|
||||
uInt8 bus[] = { 'B', 'U', 'S'};
|
||||
return searchForBytes(image, size, bus, 3, 2);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Cartridge::isProbablyCDF(const uInt8* image, uInt32 size)
|
||||
{
|
||||
// CDF ARM code has 3 occurrences of the string DPC+
|
||||
// Note: all Harmony/Melody custom drivers also contain the value
|
||||
// 0x10adab1e (LOADABLE) if needed for future improvement
|
||||
uInt8 signature[] = { 'C', 'D', 'F' };
|
||||
return searchForBytes(image, size, signature, 3, 3);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool Cartridge::isProbablyDF(const uInt8* image, uInt32 size, const char*& type)
|
||||
{
|
||||
|
@ -997,6 +1029,8 @@ Cartridge::BankswitchType Cartridge::ourBSList[ourNumBSTypes] = {
|
|||
{ "AR", "AR (Supercharger)" },
|
||||
{ "BF", "BF (CPUWIZ 256K)" },
|
||||
{ "BFSC", "BFSC (CPUWIZ 256K + ram)" },
|
||||
{ "BUS", "BUS (Bus Stuffing)" },
|
||||
{ "CDF", "CDF (Chris, Darrell, Fred)" },
|
||||
{ "CM", "CM (SpectraVideo CompuMate)" },
|
||||
{ "CTY", "CTY (CDW - Chetiry)" },
|
||||
{ "CV", "CV (Commavid extra ram)" },
|
||||
|
|
|
@ -172,6 +172,13 @@ class Cartridge : public Device
|
|||
*/
|
||||
virtual void setRomName(const string& name) { }
|
||||
|
||||
/**
|
||||
Thumbulator only supports 16-bit ARM code. Some Harmony/Melody drivers,
|
||||
such as BUS and CDF, feature 32-bit ARM code subroutines. This is used
|
||||
to pass values back to the cartridge class to emulate those subroutines.
|
||||
*/
|
||||
virtual uInt32 thumbCallback(uInt8 function, uInt32 value1, uInt32 value2) { return 0; }
|
||||
|
||||
/**
|
||||
Get debugger widget responsible for accessing the inner workings
|
||||
of the cart. This will need to be overridden and implemented by
|
||||
|
@ -187,7 +194,7 @@ class Cartridge : public Device
|
|||
const char* type;
|
||||
const char* desc;
|
||||
};
|
||||
enum { ourNumBSTypes = 48 };
|
||||
enum { ourNumBSTypes = 50 };
|
||||
static BankswitchType ourBSList[ourNumBSTypes];
|
||||
|
||||
protected:
|
||||
|
@ -303,6 +310,16 @@ class Cartridge : public Device
|
|||
*/
|
||||
static bool isProbablyBF(const uInt8* image, uInt32 size, const char*& type);
|
||||
|
||||
/**
|
||||
Returns true if the image is probably a BUS bankswitching cartridge
|
||||
*/
|
||||
static bool isProbablyBUS(const uInt8* image, uInt32 size);
|
||||
|
||||
/**
|
||||
Returns true if the image is probably a CDF bankswitching cartridge
|
||||
*/
|
||||
static bool isProbablyCDF(const uInt8* image, uInt32 size);
|
||||
|
||||
/**
|
||||
Returns true if the image is probably a CTY bankswitching cartridge
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,750 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2015 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: CartBUS.cxx 3131 2015-01-01 03:49:32Z stephena $
|
||||
//============================================================================
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
#include "Debugger.hxx"
|
||||
#endif
|
||||
#include "System.hxx"
|
||||
#include "M6532.hxx"
|
||||
#include "TIA.hxx"
|
||||
#include "Thumbulator.hxx"
|
||||
#include "CartBUS.hxx"
|
||||
|
||||
// Location of data within the RAM copy of the BUS Driver.
|
||||
#define DSxPTR 0x06E0
|
||||
#define DSxINC 0x0720
|
||||
#define DSMAPS 0x0760
|
||||
#define WAVEFORM 0x07F4
|
||||
#define DSRAM 0x0800
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeBUS::CartridgeBUS(const uInt8* image, uInt32 size,
|
||||
const Settings& settings)
|
||||
: Cartridge(settings),
|
||||
mySystemCycles(0),
|
||||
myFractionalClocks(0.0)
|
||||
{
|
||||
// Copy the ROM image into my buffer
|
||||
memcpy(myImage, image, std::min(32768u, size));
|
||||
|
||||
// even though the ROM is 32K, only 28K is accessible to the 6507
|
||||
createCodeAccessBase(4096 * 7);
|
||||
|
||||
// Pointer to the program ROM (28K @ 0 byte offset)
|
||||
// which starts after the 2K BUS Driver and 2K C Code
|
||||
myProgramImage = myImage + 4096;
|
||||
|
||||
// Pointer to BUS driver in RAM
|
||||
myBusDriverImage = myBUSRAM;
|
||||
|
||||
// Pointer to the display RAM
|
||||
myDisplayImage = myBUSRAM + DSRAM;
|
||||
|
||||
#ifdef THUMB_SUPPORT
|
||||
// Create Thumbulator ARM emulator
|
||||
myThumbEmulator = make_ptr<Thumbulator>
|
||||
((uInt16*)myImage, (uInt16*)myBUSRAM,
|
||||
settings.getBool("thumb.trapfatal"),
|
||||
Thumbulator::ConfigureFor::BUS,
|
||||
this);
|
||||
#endif
|
||||
setInitialState();
|
||||
|
||||
// BUS always starts in bank 6
|
||||
myStartBank = 6;
|
||||
|
||||
// bus stuffing is off by default
|
||||
myBusStuff = false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeBUS::~CartridgeBUS()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeBUS::reset()
|
||||
{
|
||||
// Initialize RAM
|
||||
if(mySettings.getBool("ramrandom"))
|
||||
for(uInt32 t = 2048; t < 8192; ++t)
|
||||
myBUSRAM[t] = mySystem->randGenerator().next();
|
||||
else
|
||||
memset(myBUSRAM+2048, 0, 8192-2048);
|
||||
|
||||
// Update cycles to the current system cycles
|
||||
mySystemCycles = mySystem->cycles();
|
||||
myFractionalClocks = 0.0;
|
||||
|
||||
setInitialState();
|
||||
|
||||
// Upon reset we switch to the startup bank
|
||||
bank(myStartBank);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeBUS::setInitialState()
|
||||
{
|
||||
// Copy initial BUS driver to Harmony RAM
|
||||
memcpy(myBusDriverImage, myImage, 0x0800);
|
||||
|
||||
for (int i=0; i < 3; ++i)
|
||||
myMusicWaveformSize[i] = 27;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeBUS::consoleChanged(ConsoleTiming timing)
|
||||
{
|
||||
#ifdef THUMB_SUPPORT
|
||||
myThumbEmulator->setConsoleTiming(timing);
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeBUS::systemCyclesReset()
|
||||
{
|
||||
// Adjust the cycle counter so that it reflects the new value
|
||||
mySystemCycles -= mySystem->cycles();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeBUS::install(System& system)
|
||||
{
|
||||
mySystem = &system;
|
||||
|
||||
// Map all of the accesses to call peek and poke
|
||||
System::PageAccess access(this, System::PA_READ);
|
||||
for(uInt32 i = 0x1000; i < 0x1040; i += (1 << System::PAGE_SHIFT))
|
||||
mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
|
||||
|
||||
// Mirror all access in TIA and RIOT; by doing so we're taking responsibility
|
||||
// for that address space in peek and poke below.
|
||||
mySystem->tia().installDelegate(system, *this);
|
||||
mySystem->m6532().installDelegate(system, *this);
|
||||
|
||||
// Install pages for the startup bank
|
||||
bank(myStartBank);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
inline void CartridgeBUS::updateMusicModeDataFetchers()
|
||||
{
|
||||
// Calculate the number of cycles since the last update
|
||||
Int32 cycles = mySystem->cycles() - mySystemCycles;
|
||||
mySystemCycles = mySystem->cycles();
|
||||
|
||||
// Calculate the number of BUS OSC clocks since the last update
|
||||
double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks;
|
||||
Int32 wholeClocks = Int32(clocks);
|
||||
myFractionalClocks = clocks - double(wholeClocks);
|
||||
|
||||
if(wholeClocks <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's update counters and flags of the music mode data fetchers
|
||||
for(int x = 0; x <= 2; ++x)
|
||||
{
|
||||
myMusicCounters[x] += myMusicFrequencies[x];
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
inline void CartridgeBUS::callFunction(uInt8 value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
#ifdef THUMB_SUPPORT
|
||||
// Call user written ARM code (will most likely be C compiled for ARM)
|
||||
case 254: // call with IRQ driven audio, no special handling needed at this
|
||||
// time for Stella as ARM code "runs in zero 6507 cycles".
|
||||
case 255: // call without IRQ driven audio
|
||||
try {
|
||||
myThumbEmulator->run();
|
||||
}
|
||||
catch(const runtime_error& e) {
|
||||
if(!mySystem->autodetectMode())
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
Debugger::debugger().startWithFatalError(e.what());
|
||||
#else
|
||||
cout << e.what() << endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 CartridgeBUS::peek(uInt16 address)
|
||||
{
|
||||
if(!(address & 0x1000)) // Hotspots below 0x1000
|
||||
{
|
||||
// Check for RAM or TIA mirroring
|
||||
uInt16 lowAddress = address & 0x3ff;
|
||||
if(lowAddress & 0x80)
|
||||
return mySystem->m6532().peek(address);
|
||||
else if(!(lowAddress & 0x200))
|
||||
return mySystem->tia().peek(address);
|
||||
}
|
||||
else
|
||||
{
|
||||
address &= 0x0FFF;
|
||||
|
||||
uInt8 peekvalue = myProgramImage[(myCurrentBank << 12) + address];
|
||||
|
||||
// In debugger/bank-locked mode, we ignore all hotspots and in general
|
||||
// anything that can change the internal state of the cart
|
||||
if(bankLocked())
|
||||
return peekvalue;
|
||||
|
||||
// save the STY's zero page address
|
||||
if (getBusStuffFlag() && mySTYZeroPage)
|
||||
myBusOverdriveAddress = peekvalue;
|
||||
|
||||
mySTYZeroPage = false;
|
||||
|
||||
if(address < 0x20)
|
||||
{
|
||||
uInt8 result = 0;
|
||||
|
||||
// Get the index of the data fetcher that's being accessed
|
||||
uInt32 index = address & 0x0f;
|
||||
uInt32 function = (address >> 4) & 0x01;
|
||||
|
||||
switch(function)
|
||||
{
|
||||
case 0x00: // read from a datastream
|
||||
{
|
||||
result = readFromDatastream(index);
|
||||
break;
|
||||
}
|
||||
case 0x01: // misc read registers
|
||||
{
|
||||
switch(index)
|
||||
{
|
||||
// the following are POKE ONLY
|
||||
case 0x00: // 0x10 DF0WRITE
|
||||
case 0x01: // 0x11 DF1WRITE
|
||||
case 0x02: // 0x12 DF2WRITE
|
||||
case 0x03: // 0x13 DF3WRITE
|
||||
case 0x04: // 0x14 DF0PTR
|
||||
case 0x05: // 0x15 DF1PTR
|
||||
case 0x06: // 0x16 DF2PTR
|
||||
case 0x07: // 0x17 DF3PTR
|
||||
case 0x09: // 0x19 STUFFMODE
|
||||
case 0x0a: // 0x1A CALLFN
|
||||
break;
|
||||
|
||||
case 0x08: // 0x18 = AMPLITUDE
|
||||
// Update the music data fetchers (counter & flag)
|
||||
updateMusicModeDataFetchers();
|
||||
|
||||
// using myDisplayImage[] instead of myProgramImage[] because waveforms
|
||||
// can be modified during runtime.
|
||||
uInt32 i = myDisplayImage[(getWaveform(0) ) + (myMusicCounters[0] >> myMusicWaveformSize[0])] +
|
||||
myDisplayImage[(getWaveform(1) ) + (myMusicCounters[1] >> myMusicWaveformSize[1])] +
|
||||
myDisplayImage[(getWaveform(2) ) + (myMusicCounters[2] >> myMusicWaveformSize[2])];
|
||||
|
||||
result = uInt8(i);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Switch banks if necessary
|
||||
switch(address)
|
||||
{
|
||||
case 0xFF5:
|
||||
// Set the current bank to the first 4k bank
|
||||
bank(0);
|
||||
break;
|
||||
|
||||
case 0x0FF6:
|
||||
// Set the current bank to the second 4k bank
|
||||
bank(1);
|
||||
break;
|
||||
|
||||
case 0x0FF7:
|
||||
// Set the current bank to the third 4k bank
|
||||
bank(2);
|
||||
break;
|
||||
|
||||
case 0x0FF8:
|
||||
// Set the current bank to the fourth 4k bank
|
||||
bank(3);
|
||||
break;
|
||||
|
||||
case 0x0FF9:
|
||||
// Set the current bank to the fifth 4k bank
|
||||
bank(4);
|
||||
break;
|
||||
|
||||
case 0x0FFA:
|
||||
// Set the current bank to the sixth 4k bank
|
||||
bank(5);
|
||||
break;
|
||||
|
||||
case 0x0FFB:
|
||||
// Set the current bank to the last 4k bank
|
||||
bank(6);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// this might not work right for STY $84
|
||||
if (getBusStuffFlag())
|
||||
mySTYZeroPage = (peekvalue == 0x84);
|
||||
|
||||
return peekvalue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeBUS::poke(uInt16 address, uInt8 value)
|
||||
{
|
||||
if (!(address & 0x1000))
|
||||
{
|
||||
value &= busOverdrive(address);
|
||||
|
||||
// Check for RAM or TIA mirroring
|
||||
uInt16 lowAddress = address & 0x3ff;
|
||||
if(lowAddress & 0x80)
|
||||
mySystem->m6532().poke(address, value);
|
||||
else if(!(lowAddress & 0x200))
|
||||
mySystem->tia().poke(address, value);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
address &= 0x0FFF;
|
||||
|
||||
if ((address >= 0x10) && (address <= 0x1F))
|
||||
{
|
||||
// Get the index of the data fetcher that's being accessed
|
||||
uInt32 index = address & 0x0f;
|
||||
uInt32 pointer;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 0x00: // DS0WRITE
|
||||
case 0x01: // DS1WRITE
|
||||
case 0x02: // DS2WRITE
|
||||
case 0x03: // DS3WRITE
|
||||
// Pointers are stored as:
|
||||
// PPPFF---
|
||||
//
|
||||
// P = Pointer
|
||||
// F = Fractional
|
||||
|
||||
pointer = getDatastreamPointer(index);
|
||||
myDisplayImage[ pointer >> 20 ] = value;
|
||||
pointer += 0x100000; // always increment by 1 when writing
|
||||
setDatastreamPointer(index, pointer);
|
||||
break;
|
||||
|
||||
case 0x04: // 0x14 DS0PTR
|
||||
case 0x05: // 0x15 DS1PTR
|
||||
case 0x06: // 0x16 DS2PTR
|
||||
case 0x07: // 0x17 DS3PTR
|
||||
// Pointers are stored as:
|
||||
// PPPFF---
|
||||
//
|
||||
// P = Pointer
|
||||
// F = Fractional
|
||||
|
||||
index &= 0x03;
|
||||
pointer = getDatastreamPointer(index);
|
||||
pointer <<=8;
|
||||
pointer &= 0xf0000000;
|
||||
pointer |= (value << 20);
|
||||
setDatastreamPointer(index, pointer);
|
||||
break;
|
||||
|
||||
case 0x09: // 0x19 turn on STY ZP bus stuffing if value is 0
|
||||
setBusStuffFlag(value==0);
|
||||
break;
|
||||
|
||||
case 0x0A: // 0x1A CALLFUNCTION
|
||||
callFunction(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Switch banks if necessary
|
||||
switch(address)
|
||||
{
|
||||
case 0xFF5:
|
||||
// Set the current bank to the first 4k bank
|
||||
bank(0);
|
||||
break;
|
||||
|
||||
case 0x0FF6:
|
||||
// Set the current bank to the second 4k bank
|
||||
bank(1);
|
||||
break;
|
||||
|
||||
case 0x0FF7:
|
||||
// Set the current bank to the third 4k bank
|
||||
bank(2);
|
||||
break;
|
||||
|
||||
case 0x0FF8:
|
||||
// Set the current bank to the fourth 4k bank
|
||||
bank(3);
|
||||
break;
|
||||
|
||||
case 0x0FF9:
|
||||
// Set the current bank to the fifth 4k bank
|
||||
bank(4);
|
||||
break;
|
||||
|
||||
case 0x0FFA:
|
||||
// Set the current bank to the sixth 4k bank
|
||||
bank(5);
|
||||
break;
|
||||
|
||||
case 0x0FFB:
|
||||
// Set the current bank to the last 4k bank
|
||||
bank(6);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeBUS::bank(uInt16 bank)
|
||||
{
|
||||
if(bankLocked()) return false;
|
||||
|
||||
// Remember what bank we're in
|
||||
myCurrentBank = bank;
|
||||
uInt16 offset = myCurrentBank << 12;
|
||||
|
||||
// Setup the page access methods for the current bank
|
||||
System::PageAccess access(this, System::PA_READ);
|
||||
|
||||
// Map Program ROM image into the system
|
||||
for(uInt32 address = 0x1040; address < 0x2000;
|
||||
address += (1 << System::PAGE_SHIFT))
|
||||
{
|
||||
access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
|
||||
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
||||
}
|
||||
return myBankChanged = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt16 CartridgeBUS::getBank() const
|
||||
{
|
||||
return myCurrentBank;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt16 CartridgeBUS::bankCount() const
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeBUS::patch(uInt16 address, uInt8 value)
|
||||
{
|
||||
address &= 0x0FFF;
|
||||
|
||||
// For now, we ignore attempts to patch the BUS address space
|
||||
if(address >= 0x0040)
|
||||
{
|
||||
myProgramImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
|
||||
return myBankChanged = true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const uInt8* CartridgeBUS::getImage(int& size) const
|
||||
{
|
||||
size = 32768;
|
||||
return myImage;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
uInt8 CartridgeBUS::busOverdrive(uInt16 address)
|
||||
{
|
||||
uInt8 overdrive = 0xff;
|
||||
|
||||
// Not sure how to do this, check with stephena.
|
||||
//
|
||||
// Per discussion with cd-w, have this routine check that the Y register has a
|
||||
// value of 0xFF. Of it doesn't then "crash the emulation".
|
||||
|
||||
|
||||
// only overdrive if the address matches
|
||||
if (address == myBusOverdriveAddress)
|
||||
{
|
||||
uInt8 map = address & 0x7f;
|
||||
if (map <= 0x24) // map TIA registers VSYNC thru HMBL inclusive
|
||||
{
|
||||
uInt32 alldatastreams = getAddressMap(map);
|
||||
uInt8 datastream = alldatastreams & 0x0f; // lowest nybble has the current datastream to use
|
||||
overdrive = readFromDatastream(datastream);
|
||||
|
||||
// rotate map nybbles for next time
|
||||
alldatastreams >>= 4;
|
||||
alldatastreams |= (datastream << 28);
|
||||
setAddressMap(map, alldatastreams);
|
||||
|
||||
// overdrive |= 0x7c; // breaks bus stuffing to match hobo's system
|
||||
}
|
||||
}
|
||||
|
||||
myBusOverdriveAddress = 0xff; // turns off overdrive for next poke event
|
||||
|
||||
return overdrive;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
uInt32 CartridgeBUS::thumbCallback(uInt8 function, uInt32 value1, uInt32 value2)
|
||||
{
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case 0:
|
||||
// _SetNote - set the note/frequency
|
||||
myMusicFrequencies[value1] = value2;
|
||||
break;
|
||||
|
||||
// _ResetWave - reset counter,
|
||||
// used to make sure digital samples start from the beginning
|
||||
case 1:
|
||||
myMusicCounters[value1] = 0;
|
||||
break;
|
||||
|
||||
// _GetWavePtr - return the counter
|
||||
case 2:
|
||||
return myMusicCounters[value1];
|
||||
break;
|
||||
|
||||
// _SetWaveSize - set size of waveform buffer
|
||||
case 3:
|
||||
myMusicWaveformSize[value1] = value2;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeBUS::save(Serializer& out) const
|
||||
{
|
||||
try
|
||||
{
|
||||
out.putString(name());
|
||||
|
||||
// Indicates which bank is currently active
|
||||
out.putShort(myCurrentBank);
|
||||
|
||||
// Harmony RAM
|
||||
out.putByteArray(myBUSRAM, 8192);
|
||||
|
||||
out.putInt(mySystemCycles);
|
||||
out.putInt((uInt32)(myFractionalClocks * 100000000.0));
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "ERROR: CartridgeBUS::save" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeBUS::load(Serializer& in)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(in.getString() != name())
|
||||
return false;
|
||||
|
||||
// Indicates which bank is currently active
|
||||
myCurrentBank = in.getShort();
|
||||
|
||||
// Harmony RAM
|
||||
in.getByteArray(myBUSRAM, 8192);
|
||||
|
||||
// Get system cycles and fractional clocks
|
||||
mySystemCycles = (Int32)in.getInt();
|
||||
myFractionalClocks = (double)in.getInt() / 100000000.0;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "ERROR: CartridgeBUS::load" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now, go to the current bank
|
||||
bank(myCurrentBank);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uInt32 CartridgeBUS::getDatastreamPointer(uInt8 index)
|
||||
{
|
||||
// index &= 0x0f;
|
||||
|
||||
return myBUSRAM[DSxPTR + index*4 + 0] + // low byte
|
||||
(myBUSRAM[DSxPTR + index*4 + 1] << 8) +
|
||||
(myBUSRAM[DSxPTR + index*4 + 2] << 16) +
|
||||
(myBUSRAM[DSxPTR + index*4 + 3] << 24) ; // high byte
|
||||
}
|
||||
|
||||
void CartridgeBUS::setDatastreamPointer(uInt8 index, uInt32 value)
|
||||
{
|
||||
// index &= 0x0f;
|
||||
myBUSRAM[DSxPTR + index*4 + 0] = value & 0xff; // low byte
|
||||
myBUSRAM[DSxPTR + index*4 + 1] = (value >> 8) & 0xff;
|
||||
myBUSRAM[DSxPTR + index*4 + 2] = (value >> 16) & 0xff;
|
||||
myBUSRAM[DSxPTR + index*4 + 3] = (value >> 24) & 0xff; // high byte
|
||||
}
|
||||
|
||||
uInt32 CartridgeBUS::getDatastreamIncrement(uInt8 index)
|
||||
{
|
||||
// index &= 0x0f;
|
||||
return myBUSRAM[DSxINC + index*4 + 0] + // low byte
|
||||
(myBUSRAM[DSxINC + index*4 + 1] << 8) +
|
||||
(myBUSRAM[DSxINC + index*4 + 2] << 16) +
|
||||
(myBUSRAM[DSxINC + index*4 + 3] << 24) ; // high byte
|
||||
}
|
||||
|
||||
void CartridgeBUS::setDatastreamIncrement(uInt8 index, uInt32 value)
|
||||
{
|
||||
// index &= 0x0f;
|
||||
myBUSRAM[DSxINC + index*4 + 0] = value & 0xff; // low byte
|
||||
myBUSRAM[DSxINC + index*4 + 1] = (value >> 8) & 0xff;
|
||||
myBUSRAM[DSxINC + index*4 + 2] = (value >> 16) & 0xff;
|
||||
myBUSRAM[DSxINC + index*4 + 3] = (value >> 24) & 0xff; // high byte
|
||||
}
|
||||
|
||||
uInt32 CartridgeBUS::getAddressMap(uInt8 index)
|
||||
{
|
||||
// index &= 0x0f;
|
||||
return myBUSRAM[DSMAPS + index*4 + 0] + // low byte
|
||||
(myBUSRAM[DSMAPS + index*4 + 1] << 8) +
|
||||
(myBUSRAM[DSMAPS + index*4 + 2] << 16) +
|
||||
(myBUSRAM[DSMAPS + index*4 + 3] << 24) ; // high byte
|
||||
}
|
||||
|
||||
uInt32 CartridgeBUS::getWaveform(uInt8 index)
|
||||
{
|
||||
// instead of 0, 1, 2, etc. this returned
|
||||
// 0x40000800 for 0
|
||||
// 0x40000820 for 1
|
||||
// 0x40000840 for 2
|
||||
// ...
|
||||
|
||||
// return myBUSRAM[WAVEFORM + index*4 + 0] + // low byte
|
||||
// (myBUSRAM[WAVEFORM + index*4 + 1] << 8) +
|
||||
// (myBUSRAM[WAVEFORM + index*4 + 2] << 16) +
|
||||
// (myBUSRAM[WAVEFORM + index*4 + 3] << 24) - // high byte
|
||||
// 0x40000800;
|
||||
|
||||
uInt32 result;
|
||||
|
||||
result = myBUSRAM[WAVEFORM + index*4 + 0] + // low byte
|
||||
(myBUSRAM[WAVEFORM + index*4 + 1] << 8) +
|
||||
(myBUSRAM[WAVEFORM + index*4 + 2] << 16) +
|
||||
(myBUSRAM[WAVEFORM + index*4 + 3] << 24);
|
||||
|
||||
result -= 0x40000800;
|
||||
|
||||
if (result >= 4096)
|
||||
result = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uInt32 CartridgeBUS::getWaveformSize(uInt8 index)
|
||||
{
|
||||
return myMusicWaveformSize[index];
|
||||
}
|
||||
|
||||
void CartridgeBUS::setAddressMap(uInt8 index, uInt32 value)
|
||||
{
|
||||
// index &= 0x0f;
|
||||
myBUSRAM[DSMAPS + index*4 + 0] = value & 0xff; // low byte
|
||||
myBUSRAM[DSMAPS + index*4 + 1] = (value >> 8) & 0xff;
|
||||
myBUSRAM[DSMAPS + index*4 + 2] = (value >> 16) & 0xff;
|
||||
myBUSRAM[DSMAPS + index*4 + 3] = (value >> 24) & 0xff; // high byte
|
||||
}
|
||||
|
||||
bool CartridgeBUS::getBusStuffFlag(void)
|
||||
{
|
||||
return myBusStuff;
|
||||
}
|
||||
|
||||
void CartridgeBUS::setBusStuffFlag(bool value)
|
||||
{
|
||||
myBusStuff = value;
|
||||
}
|
||||
|
||||
uInt8 CartridgeBUS::readFromDatastream(uInt8 index)
|
||||
{
|
||||
// Pointers are stored as:
|
||||
// PPPFF---
|
||||
//
|
||||
// Increments are stored as
|
||||
// ----IIFF
|
||||
//
|
||||
// P = Pointer
|
||||
// I = Increment
|
||||
// F = Fractional
|
||||
|
||||
uInt32 pointer = getDatastreamPointer(index);
|
||||
uInt16 increment = getDatastreamIncrement(index);
|
||||
uInt8 value = myDisplayImage[ pointer >> 20 ];
|
||||
pointer += (increment << 12);
|
||||
setDatastreamPointer(index, pointer);
|
||||
return value;
|
||||
}
|
||||
|
|
@ -0,0 +1,287 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2015 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: CartBUS.hxx 3131 2015-01-01 03:49:32Z stephena $
|
||||
//============================================================================
|
||||
|
||||
#ifndef CARTRIDGE_BUS_HXX
|
||||
#define CARTRIDGE_BUS_HXX
|
||||
|
||||
class System;
|
||||
#ifdef THUMB_SUPPORT
|
||||
class Thumbulator;
|
||||
#endif
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
#include "CartBUSWidget.hxx"
|
||||
#endif
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Cart.hxx"
|
||||
|
||||
/**
|
||||
Cartridge class used for BUS.
|
||||
|
||||
THIS NEEDS TO BE UPDATED
|
||||
|
||||
|
||||
There are seven 4K program banks, a 4K Display Data RAM,
|
||||
1K C Varaible and Stack, and the BUS chip.
|
||||
BUS chip access is mapped to $1000 - $103F.
|
||||
|
||||
@author Darrell Spice Jr, Chris Walton, Fred Quimby, Stephen Anthony, Bradford W. Mott
|
||||
@version $Id: CartBUS.hxx 3131 2015-01-01 03:49:32Z stephena $
|
||||
*/
|
||||
class CartridgeBUS : public Cartridge
|
||||
{
|
||||
friend class CartridgeBUSWidget;
|
||||
friend class CartridgeRamBUSWidget;
|
||||
|
||||
public:
|
||||
/**
|
||||
Create a new cartridge using the specified image
|
||||
|
||||
@param image Pointer to the ROM image
|
||||
@param size The size of the ROM image
|
||||
@param settings A reference to the various settings (read-only)
|
||||
*/
|
||||
CartridgeBUS(const uInt8* image, uInt32 size, const Settings& settings);
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~CartridgeBUS();
|
||||
|
||||
public:
|
||||
/**
|
||||
Reset device to its power-on state
|
||||
*/
|
||||
void reset() override;
|
||||
|
||||
/**
|
||||
Notification method invoked by the system when the console type
|
||||
has changed. We need this to inform the Thumbulator that the
|
||||
timing has changed.
|
||||
|
||||
@param timing Enum representing the new console type
|
||||
*/
|
||||
void consoleChanged(ConsoleTiming timing) override;
|
||||
|
||||
/**
|
||||
Notification method invoked by the system right before the
|
||||
system resets its cycle counter to zero. It may be necessary
|
||||
to override this method for devices that remember cycle counts.
|
||||
*/
|
||||
void systemCyclesReset() override;
|
||||
|
||||
/**
|
||||
Install cartridge in the specified system. Invoked by the system
|
||||
when the cartridge is attached to it.
|
||||
|
||||
@param system The system the device should install itself in
|
||||
*/
|
||||
void install(System& system) override;
|
||||
|
||||
/**
|
||||
Install pages for the specified bank in the system.
|
||||
|
||||
@param bank The bank that should be installed in the system
|
||||
*/
|
||||
bool bank(uInt16 bank) override;
|
||||
|
||||
/**
|
||||
Get the current bank.
|
||||
*/
|
||||
uInt16 getBank() const override;
|
||||
|
||||
/**
|
||||
Query the number of banks supported by the cartridge.
|
||||
*/
|
||||
uInt16 bankCount() const override;
|
||||
|
||||
/**
|
||||
Patch the cartridge ROM.
|
||||
|
||||
@param address The ROM address to patch
|
||||
@param value The value to place into the address
|
||||
@return Success or failure of the patch operation
|
||||
*/
|
||||
bool patch(uInt16 address, uInt8 value) override;
|
||||
|
||||
/**
|
||||
Access the internal ROM image for this cartridge.
|
||||
|
||||
@param size Set to the size of the internal ROM image data
|
||||
@return A pointer to the internal ROM image data
|
||||
*/
|
||||
const uInt8* getImage(int& size) const override;
|
||||
|
||||
/**
|
||||
Save the current state of this cart to the given Serializer.
|
||||
|
||||
@param out The Serializer object to use
|
||||
@return False on any errors, else true
|
||||
*/
|
||||
bool save(Serializer& out) const override;
|
||||
|
||||
/**
|
||||
Load the current state of this cart from the given Serializer.
|
||||
|
||||
@param in The Serializer object to use
|
||||
@return False on any errors, else true
|
||||
*/
|
||||
bool load(Serializer& in) override;
|
||||
|
||||
/**
|
||||
Get a descriptor for the device name (used in error checking).
|
||||
|
||||
@return The name of the object
|
||||
*/
|
||||
string name() const override { return "CartridgeBUS"; }
|
||||
|
||||
uInt8 busOverdrive(uInt16 address);
|
||||
|
||||
/**
|
||||
Used for Thumbulator to pass values back to the cartridge
|
||||
*/
|
||||
uInt32 thumbCallback(uInt8 function, uInt32 value1, uInt32 value2) override;
|
||||
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
/**
|
||||
Get debugger widget responsible for accessing the inner workings
|
||||
of the cart.
|
||||
*/
|
||||
CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
const GUI::Font& nfont, int x, int y, int w, int h) override
|
||||
{
|
||||
return new CartridgeBUSWidget(boss, lfont, nfont, x, y, w, h, *this);
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
/**
|
||||
Get the byte at the specified address.
|
||||
|
||||
@return The byte at the specified address
|
||||
*/
|
||||
uInt8 peek(uInt16 address) override;
|
||||
|
||||
/**
|
||||
Change the byte at the specified address to the given value
|
||||
|
||||
@param address The address where the value should be stored
|
||||
@param value The value to be stored at the address
|
||||
@return True if the poke changed the device address space, else false
|
||||
*/
|
||||
bool poke(uInt16 address, uInt8 value) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
Sets the initial state of the DPC pointers and RAM
|
||||
*/
|
||||
void setInitialState();
|
||||
|
||||
/**
|
||||
Updates any data fetchers in music mode based on the number of
|
||||
CPU cycles which have passed since the last update.
|
||||
*/
|
||||
void updateMusicModeDataFetchers();
|
||||
|
||||
/**
|
||||
Call Special Functions
|
||||
*/
|
||||
void callFunction(uInt8 value);
|
||||
|
||||
uInt32 getDatastreamPointer(uInt8 index);
|
||||
void setDatastreamPointer(uInt8 index, uInt32 value);
|
||||
|
||||
uInt32 getDatastreamIncrement(uInt8 index);
|
||||
void setDatastreamIncrement(uInt8 index, uInt32 value);
|
||||
|
||||
uInt32 getAddressMap(uInt8 index);
|
||||
void setAddressMap(uInt8 index, uInt32 value);
|
||||
|
||||
bool getBusStuffFlag(void);
|
||||
void setBusStuffFlag(bool value);
|
||||
|
||||
uInt8 readFromDatastream(uInt8 index);
|
||||
|
||||
uInt32 getWaveform(uInt8 index);
|
||||
uInt32 getWaveformSize(uInt8 index);
|
||||
|
||||
private:
|
||||
// The 32K ROM image of the cartridge
|
||||
uInt8 myImage[32768];
|
||||
|
||||
// Pointer to the 28K program ROM image of the cartridge
|
||||
uInt8* myProgramImage;
|
||||
|
||||
// Pointer to the 4K display ROM image of the cartridge
|
||||
uInt8* myDisplayImage;
|
||||
|
||||
// Pointer to the 2K BUS driver image in RAM
|
||||
uInt8* myBusDriverImage;
|
||||
|
||||
// The BUS 8k RAM image, used as:
|
||||
// $0000 - 2K BUS driver
|
||||
// $0800 - 4K Display Data
|
||||
// $1800 - 2K C Variable & Stack
|
||||
uInt8 myBUSRAM[8192];
|
||||
|
||||
#ifdef THUMB_SUPPORT
|
||||
// Pointer to the Thumb ARM emulator object
|
||||
unique_ptr<Thumbulator> myThumbEmulator;
|
||||
#endif
|
||||
|
||||
// Indicates which bank is currently active
|
||||
uInt16 myCurrentBank;
|
||||
|
||||
// Address to override the bus for
|
||||
uInt16 myBusOverdriveAddress;
|
||||
|
||||
// Flags that last byte peeked was 84 (STY ZP)
|
||||
bool mySTYZeroPage;
|
||||
|
||||
// System cycle count when the last update to music data fetchers occurred
|
||||
Int32 mySystemCycles;
|
||||
|
||||
uInt8 mySetAddress;
|
||||
|
||||
// The music mode counters
|
||||
uInt32 myMusicCounters[3];
|
||||
|
||||
// The music frequency
|
||||
uInt32 myMusicFrequencies[3];
|
||||
|
||||
// The music waveform sizes
|
||||
uInt8 myMusicWaveformSize[3];
|
||||
|
||||
// Fractional DPC music OSC clocks unused during the last update
|
||||
double myFractionalClocks;
|
||||
|
||||
// Flags that Bus Stuffing is active
|
||||
bool myBusStuff;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
CartridgeBUS() = delete;
|
||||
CartridgeBUS(const CartridgeBUS&) = delete;
|
||||
CartridgeBUS(CartridgeBUS&&) = delete;
|
||||
CartridgeBUS& operator=(const CartridgeBUS&) = delete;
|
||||
CartridgeBUS& operator=(CartridgeBUS&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,659 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2015 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: CartCDF.cxx 3131 2015-01-01 03:49:32Z stephena $
|
||||
//============================================================================
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
#include "Debugger.hxx"
|
||||
#endif
|
||||
#include "System.hxx"
|
||||
#include "Thumbulator.hxx"
|
||||
#include "CartCDF.hxx"
|
||||
#include "TIA.hxx"
|
||||
|
||||
// Location of data within the RAM copy of the CDF Driver.
|
||||
#define DSxPTR 0x06E0
|
||||
#define DSxINC 0x0760
|
||||
#define WAVEFORM 0x07E0
|
||||
#define DSRAM 0x0800
|
||||
|
||||
#define FAST_FETCH_ON ((myMode & 0x0F) == 0)
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeCDF::CartridgeCDF(const uInt8* image, uInt32 size,
|
||||
const Settings& settings)
|
||||
: Cartridge(settings),
|
||||
mySystemCycles(0),
|
||||
myARMCycles(0),
|
||||
myFractionalClocks(0.0)
|
||||
{
|
||||
// Copy the ROM image into my buffer
|
||||
memcpy(myImage, image, std::min(32768u, size));
|
||||
|
||||
// even though the ROM is 32K, only 28K is accessible to the 6507
|
||||
createCodeAccessBase(4096 * 7);
|
||||
|
||||
// Pointer to the program ROM (28K @ 0 byte offset)
|
||||
// which starts after the 2K CDF Driver and 2K C Code
|
||||
myProgramImage = myImage + 4096;
|
||||
|
||||
// Pointer to CDF driver in RAM
|
||||
myBusDriverImage = myCDFRAM;
|
||||
|
||||
// Pointer to the display RAM
|
||||
myDisplayImage = myCDFRAM + DSRAM;
|
||||
#ifdef THUMB_SUPPORT
|
||||
// Create Thumbulator ARM emulator
|
||||
myThumbEmulator = make_ptr<Thumbulator>
|
||||
((uInt16*)myImage, (uInt16*)myCDFRAM,
|
||||
settings.getBool("thumb.trapfatal"),
|
||||
Thumbulator::ConfigureFor::CDF,
|
||||
this);
|
||||
#endif
|
||||
setInitialState();
|
||||
|
||||
// CDF always starts in bank 6
|
||||
myStartBank = 6;
|
||||
|
||||
// Assuming mode starts out with Fast Fetch off and 3-Voice music,
|
||||
// need to confirm with Chris
|
||||
myMode = 0xFF;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
CartridgeCDF::~CartridgeCDF()
|
||||
{
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeCDF::reset()
|
||||
{
|
||||
// Initialize RAM
|
||||
if(mySettings.getBool("ramrandom"))
|
||||
for(uInt32 t = 2048; t < 8192; ++t)
|
||||
myCDFRAM[t] = mySystem->randGenerator().next();
|
||||
else
|
||||
memset(myCDFRAM+2048, 0, 8192-2048);
|
||||
|
||||
// Update cycles to the current system cycles
|
||||
mySystemCycles = mySystem->cycles();
|
||||
myARMCycles = mySystem->cycles();
|
||||
myFractionalClocks = 0.0;
|
||||
|
||||
setInitialState();
|
||||
|
||||
// Upon reset we switch to the startup bank
|
||||
bank(myStartBank);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeCDF::setInitialState()
|
||||
{
|
||||
// Copy initial CDF driver to Harmony RAM
|
||||
memcpy(myBusDriverImage, myImage, 0x0800);
|
||||
|
||||
for (int i=0; i < 3; ++i)
|
||||
myMusicWaveformSize[i] = 27;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeCDF::consoleChanged(ConsoleTiming timing)
|
||||
{
|
||||
#ifdef THUMB_SUPPORT
|
||||
myThumbEmulator->setConsoleTiming(timing);
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeCDF::systemCyclesReset()
|
||||
{
|
||||
// Adjust the cycle counter so that it reflects the new value
|
||||
mySystemCycles -= mySystem->cycles();
|
||||
myARMCycles -= mySystem->cycles();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeCDF::install(System& system)
|
||||
{
|
||||
mySystem = &system;
|
||||
|
||||
// Map all of the accesses to call peek and poke
|
||||
System::PageAccess access(this, System::PA_READ);
|
||||
for(uInt32 i = 0x1000; i < 0x1040; i += (1 << System::PAGE_SHIFT))
|
||||
mySystem->setPageAccess(i >> System::PAGE_SHIFT, access);
|
||||
|
||||
// Install pages for the startup bank
|
||||
bank(myStartBank);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
inline void CartridgeCDF::updateMusicModeDataFetchers()
|
||||
{
|
||||
// Calculate the number of cycles since the last update
|
||||
Int32 cycles = mySystem->cycles() - mySystemCycles;
|
||||
mySystemCycles = mySystem->cycles();
|
||||
|
||||
// Calculate the number of CDF OSC clocks since the last update
|
||||
double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks;
|
||||
Int32 wholeClocks = Int32(clocks);
|
||||
myFractionalClocks = clocks - double(wholeClocks);
|
||||
|
||||
if(wholeClocks <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's update counters and flags of the music mode data fetchers
|
||||
for(int x = 0; x <= 2; ++x)
|
||||
{
|
||||
myMusicCounters[x] += myMusicFrequencies[x];
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
inline void CartridgeCDF::callFunction(uInt8 value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
#ifdef THUMB_SUPPORT
|
||||
// Call user written ARM code (will most likely be C compiled for ARM)
|
||||
case 254: // call with IRQ driven audio, no special handling needed at this
|
||||
// time for Stella as ARM code "runs in zero 6507 cycles".
|
||||
case 255: // call without IRQ driven audio
|
||||
try {
|
||||
Int32 cycles = mySystem->cycles() - myARMCycles;
|
||||
myARMCycles = mySystem->cycles();
|
||||
|
||||
myThumbEmulator->run(cycles);
|
||||
}
|
||||
catch(const runtime_error& e) {
|
||||
if(!mySystem->autodetectMode())
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
Debugger::debugger().startWithFatalError(e.what());
|
||||
#else
|
||||
cout << e.what() << endl;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt8 CartridgeCDF::peek(uInt16 address)
|
||||
{
|
||||
address &= 0x0FFF;
|
||||
|
||||
uInt8 peekvalue = myProgramImage[(myCurrentBank << 12) + address];
|
||||
|
||||
// In debugger/bank-locked mode, we ignore all hotspots and in general
|
||||
// anything that can change the internal state of the cart
|
||||
if(bankLocked())
|
||||
return peekvalue;
|
||||
|
||||
// Check if we're in Fast Fetch mode and the prior byte was an A9 (LDA #value)
|
||||
if(FAST_FETCH_ON && myLDAimmediateOperandAddress == address)
|
||||
{
|
||||
if(peekvalue < 0x0028)
|
||||
// if #value is a read-register then we want to use that as the address
|
||||
address = peekvalue;
|
||||
}
|
||||
myLDAimmediateOperandAddress = 0;
|
||||
|
||||
|
||||
if(address <= 0x20)
|
||||
{
|
||||
uInt8 result = 0;
|
||||
|
||||
// Get the index of the data fetcher that's being accessed
|
||||
uInt32 index = address & 0x1f;
|
||||
uInt32 function = (address >> 5) & 0x01;
|
||||
|
||||
switch(function)
|
||||
{
|
||||
case 0x00: // read from a datastream
|
||||
{
|
||||
result = readFromDatastream(index);
|
||||
break;
|
||||
}
|
||||
case 0x02: // misc read registers
|
||||
{
|
||||
// index will be 0 for address 0x20 = AMPLITUDE
|
||||
// Update the music data fetchers (counter & flag)
|
||||
updateMusicModeDataFetchers();
|
||||
|
||||
// using myDisplayImage[] instead of myProgramImage[] because waveforms
|
||||
// can be modified during runtime.
|
||||
uInt32 i = myDisplayImage[(getWaveform(0) ) + (myMusicCounters[0] >> myMusicWaveformSize[0])] +
|
||||
myDisplayImage[(getWaveform(1) ) + (myMusicCounters[1] >> myMusicWaveformSize[1])] +
|
||||
myDisplayImage[(getWaveform(2) ) + (myMusicCounters[2] >> myMusicWaveformSize[2])];
|
||||
|
||||
result = uInt8(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Switch banks if necessary
|
||||
switch(address)
|
||||
{
|
||||
case 0xFF5:
|
||||
// Set the current bank to the first 4k bank
|
||||
bank(0);
|
||||
break;
|
||||
|
||||
case 0x0FF6:
|
||||
// Set the current bank to the second 4k bank
|
||||
bank(1);
|
||||
break;
|
||||
|
||||
case 0x0FF7:
|
||||
// Set the current bank to the third 4k bank
|
||||
bank(2);
|
||||
break;
|
||||
|
||||
case 0x0FF8:
|
||||
// Set the current bank to the fourth 4k bank
|
||||
bank(3);
|
||||
break;
|
||||
|
||||
case 0x0FF9:
|
||||
// Set the current bank to the fifth 4k bank
|
||||
bank(4);
|
||||
break;
|
||||
|
||||
case 0x0FFA:
|
||||
// Set the current bank to the sixth 4k bank
|
||||
bank(5);
|
||||
break;
|
||||
|
||||
case 0x0FFB:
|
||||
// Set the current bank to the last 4k bank
|
||||
bank(6);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(FAST_FETCH_ON && peekvalue == 0xA9)
|
||||
myLDAimmediateOperandAddress = address + 1;
|
||||
|
||||
return peekvalue;
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeCDF::poke(uInt16 address, uInt8 value)
|
||||
{
|
||||
address &= 0x0FFF;
|
||||
|
||||
if ((address >= 0x21) && (address <= 0x2B))
|
||||
{
|
||||
// Get the index of the data fetcher that's being accessed
|
||||
uInt32 index = address & 0x0f;
|
||||
uInt32 pointer;
|
||||
uInt32 stream = address & 0x03;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 0x00: // 0x20 AMPLITUDE - read register
|
||||
break;
|
||||
|
||||
case 0x01: // 0x21 SETMODE
|
||||
myMode = value;
|
||||
break;
|
||||
|
||||
case 0x02: // 0x22 CALLFN
|
||||
callFunction(value);
|
||||
break;
|
||||
|
||||
case 0x03: // 0x23 RESERVED
|
||||
break;
|
||||
|
||||
|
||||
case 0x04: // 0x24 DS0WRITE
|
||||
case 0x05: // 0x25 DS1WRITE
|
||||
case 0x06: // 0x26 DS2WRITE
|
||||
case 0x07: // 0x27 DS3WRITE
|
||||
// Pointers are stored as:
|
||||
// PPPFF---
|
||||
//
|
||||
// P = Pointer
|
||||
// F = Fractional
|
||||
|
||||
pointer = getDatastreamPointer(stream);
|
||||
myDisplayImage[ pointer >> 20 ] = value;
|
||||
pointer += 0x100000; // always increment by 1 when writing
|
||||
setDatastreamPointer(stream, pointer);
|
||||
break;
|
||||
|
||||
case 0x08: // 0x28 DS0PTR
|
||||
case 0x09: // 0x29 DS1PTR
|
||||
case 0x0A: // 0x2A DS2PTR
|
||||
case 0x0B: // 0x2B DS3PTR
|
||||
// Pointers are stored as:
|
||||
// PPPFF---
|
||||
//
|
||||
// P = Pointer
|
||||
// F = Fractional
|
||||
|
||||
pointer = getDatastreamPointer(stream);
|
||||
pointer <<=8;
|
||||
pointer &= 0xf0000000;
|
||||
pointer |= (value << 20);
|
||||
setDatastreamPointer(stream, pointer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Switch banks if necessary
|
||||
switch(address)
|
||||
{
|
||||
case 0xFF5:
|
||||
// Set the current bank to the first 4k bank
|
||||
bank(0);
|
||||
break;
|
||||
|
||||
case 0x0FF6:
|
||||
// Set the current bank to the second 4k bank
|
||||
bank(1);
|
||||
break;
|
||||
|
||||
case 0x0FF7:
|
||||
// Set the current bank to the third 4k bank
|
||||
bank(2);
|
||||
break;
|
||||
|
||||
case 0x0FF8:
|
||||
// Set the current bank to the fourth 4k bank
|
||||
bank(3);
|
||||
break;
|
||||
|
||||
case 0x0FF9:
|
||||
// Set the current bank to the fifth 4k bank
|
||||
bank(4);
|
||||
break;
|
||||
|
||||
case 0x0FFA:
|
||||
// Set the current bank to the sixth 4k bank
|
||||
bank(5);
|
||||
break;
|
||||
|
||||
case 0x0FFB:
|
||||
// Set the current bank to the last 4k bank
|
||||
bank(6);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeCDF::bank(uInt16 bank)
|
||||
{
|
||||
if(bankLocked()) return false;
|
||||
|
||||
// Remember what bank we're in
|
||||
myCurrentBank = bank;
|
||||
uInt16 offset = myCurrentBank << 12;
|
||||
|
||||
// Setup the page access methods for the current bank
|
||||
System::PageAccess access(this, System::PA_READ);
|
||||
|
||||
// Map Program ROM image into the system
|
||||
for(uInt32 address = 0x1040; address < 0x2000;
|
||||
address += (1 << System::PAGE_SHIFT))
|
||||
{
|
||||
access.codeAccessBase = &myCodeAccessBase[offset + (address & 0x0FFF)];
|
||||
mySystem->setPageAccess(address >> System::PAGE_SHIFT, access);
|
||||
}
|
||||
return myBankChanged = true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt16 CartridgeCDF::getBank() const
|
||||
{
|
||||
return myCurrentBank;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
uInt16 CartridgeCDF::bankCount() const
|
||||
{
|
||||
return 7;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeCDF::patch(uInt16 address, uInt8 value)
|
||||
{
|
||||
address &= 0x0FFF;
|
||||
|
||||
// For now, we ignore attempts to patch the CDF address space
|
||||
if(address >= 0x0040)
|
||||
{
|
||||
myProgramImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value;
|
||||
return myBankChanged = true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
const uInt8* CartridgeCDF::getImage(int& size) const
|
||||
{
|
||||
size = 32768;
|
||||
return myImage;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
uInt32 CartridgeCDF::thumbCallback(uInt8 function, uInt32 value1, uInt32 value2)
|
||||
{
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case 0:
|
||||
// _SetNote - set the note/frequency
|
||||
myMusicFrequencies[value1] = value2;
|
||||
break;
|
||||
|
||||
// _ResetWave - reset counter,
|
||||
// used to make sure digital samples start from the beginning
|
||||
case 1:
|
||||
myMusicCounters[value1] = 0;
|
||||
break;
|
||||
|
||||
// _GetWavePtr - return the counter
|
||||
case 2:
|
||||
return myMusicCounters[value1];
|
||||
break;
|
||||
|
||||
// _SetWaveSize - set size of waveform buffer
|
||||
case 3:
|
||||
myMusicWaveformSize[value1] = value2;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeCDF::save(Serializer& out) const
|
||||
{
|
||||
try
|
||||
{
|
||||
out.putString(name());
|
||||
|
||||
// Indicates which bank is currently active
|
||||
out.putShort(myCurrentBank);
|
||||
|
||||
// Harmony RAM
|
||||
out.putByteArray(myCDFRAM, 8192);
|
||||
|
||||
out.putInt(mySystemCycles);
|
||||
out.putInt((uInt32)(myFractionalClocks * 100000000.0));
|
||||
out.putInt(myARMCycles);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "ERROR: CartridgeCDF::save" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeCDF::load(Serializer& in)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(in.getString() != name())
|
||||
return false;
|
||||
|
||||
// Indicates which bank is currently active
|
||||
myCurrentBank = in.getShort();
|
||||
|
||||
// Harmony RAM
|
||||
in.getByteArray(myCDFRAM, 8192);
|
||||
|
||||
// Get system cycles and fractional clocks
|
||||
mySystemCycles = (Int32)in.getInt();
|
||||
myFractionalClocks = (double)in.getInt() / 100000000.0;
|
||||
|
||||
myARMCycles = (Int32)in.getInt();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "ERROR: CartridgeCDF::load" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now, go to the current bank
|
||||
bank(myCurrentBank);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uInt32 CartridgeCDF::getDatastreamPointer(uInt8 index)
|
||||
{
|
||||
// index &= 0x0f;
|
||||
|
||||
return myCDFRAM[DSxPTR + index*4 + 0] + // low byte
|
||||
(myCDFRAM[DSxPTR + index*4 + 1] << 8) +
|
||||
(myCDFRAM[DSxPTR + index*4 + 2] << 16) +
|
||||
(myCDFRAM[DSxPTR + index*4 + 3] << 24) ; // high byte
|
||||
}
|
||||
|
||||
void CartridgeCDF::setDatastreamPointer(uInt8 index, uInt32 value)
|
||||
{
|
||||
// index &= 0x1f;
|
||||
myCDFRAM[DSxPTR + index*4 + 0] = value & 0xff; // low byte
|
||||
myCDFRAM[DSxPTR + index*4 + 1] = (value >> 8) & 0xff;
|
||||
myCDFRAM[DSxPTR + index*4 + 2] = (value >> 16) & 0xff;
|
||||
myCDFRAM[DSxPTR + index*4 + 3] = (value >> 24) & 0xff; // high byte
|
||||
}
|
||||
|
||||
uInt32 CartridgeCDF::getDatastreamIncrement(uInt8 index)
|
||||
{
|
||||
// index &= 0x1f;
|
||||
return myCDFRAM[DSxINC + index*4 + 0] + // low byte
|
||||
(myCDFRAM[DSxINC + index*4 + 1] << 8) +
|
||||
(myCDFRAM[DSxINC + index*4 + 2] << 16) +
|
||||
(myCDFRAM[DSxINC + index*4 + 3] << 24) ; // high byte
|
||||
}
|
||||
|
||||
void CartridgeCDF::setDatastreamIncrement(uInt8 index, uInt32 value)
|
||||
{
|
||||
// index &= 0x1f;
|
||||
myCDFRAM[DSxINC + index*4 + 0] = value & 0xff; // low byte
|
||||
myCDFRAM[DSxINC + index*4 + 1] = (value >> 8) & 0xff;
|
||||
myCDFRAM[DSxINC + index*4 + 2] = (value >> 16) & 0xff;
|
||||
myCDFRAM[DSxINC + index*4 + 3] = (value >> 24) & 0xff; // high byte
|
||||
}
|
||||
|
||||
|
||||
uInt32 CartridgeCDF::getWaveform(uInt8 index)
|
||||
{
|
||||
// instead of 0, 1, 2, etc. this returned
|
||||
// 0x40000800 for 0
|
||||
// 0x40000820 for 1
|
||||
// 0x40000840 for 2
|
||||
// ...
|
||||
|
||||
// return myCDFRAM[WAVEFORM + index*4 + 0] + // low byte
|
||||
// (myCDFRAM[WAVEFORM + index*4 + 1] << 8) +
|
||||
// (myCDFRAM[WAVEFORM + index*4 + 2] << 16) +
|
||||
// (myCDFRAM[WAVEFORM + index*4 + 3] << 24) - // high byte
|
||||
// 0x40000800;
|
||||
|
||||
uInt32 result;
|
||||
|
||||
result = myCDFRAM[WAVEFORM + index*4 + 0] + // low byte
|
||||
(myCDFRAM[WAVEFORM + index*4 + 1] << 8) +
|
||||
(myCDFRAM[WAVEFORM + index*4 + 2] << 16) +
|
||||
(myCDFRAM[WAVEFORM + index*4 + 3] << 24);
|
||||
|
||||
result -= 0x40000800;
|
||||
|
||||
if (result >= 4096)
|
||||
result = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uInt32 CartridgeCDF::getWaveformSize(uInt8 index)
|
||||
{
|
||||
return myMusicWaveformSize[index];
|
||||
}
|
||||
|
||||
uInt8 CartridgeCDF::readFromDatastream(uInt8 index)
|
||||
{
|
||||
// Pointers are stored as:
|
||||
// PPPFF---
|
||||
//
|
||||
// Increments are stored as
|
||||
// ----IIFF
|
||||
//
|
||||
// P = Pointer
|
||||
// I = Increment
|
||||
// F = Fractional
|
||||
|
||||
uInt32 pointer = getDatastreamPointer(index);
|
||||
uInt16 increment = getDatastreamIncrement(index);
|
||||
uInt8 value = myDisplayImage[ pointer >> 20 ];
|
||||
pointer += (increment << 12);
|
||||
setDatastreamPointer(index, pointer);
|
||||
return value;
|
||||
}
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2015 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//
|
||||
// $Id: CartCDF.hxx 3131 2015-01-01 03:49:32Z stephena $
|
||||
//============================================================================
|
||||
|
||||
#ifndef CARTRIDGE_CDF_HXX
|
||||
#define CARTRIDGE_CDF_HXX
|
||||
|
||||
class System;
|
||||
#ifdef THUMB_SUPPORT
|
||||
class Thumbulator;
|
||||
#endif
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
#include "CartCDFWidget.hxx"
|
||||
#endif
|
||||
#include "bspf.hxx"
|
||||
#include "Cart.hxx"
|
||||
|
||||
/**
|
||||
Cartridge class used for CDF.
|
||||
|
||||
THIS NEEDS TO BE UPDATED
|
||||
|
||||
|
||||
There are seven 4K program banks, a 4K Display Data RAM,
|
||||
1K C Varaible and Stack, and the CDF chip.
|
||||
CDF chip access is mapped to $1000 - $103F.
|
||||
|
||||
@author Darrell Spice Jr, Chris Walton, Fred Quimby, Stephen Anthony, Bradford W. Mott
|
||||
@version $Id: CartCDF.hxx 3131 2015-01-01 03:49:32Z stephena $
|
||||
*/
|
||||
class CartridgeCDF : public Cartridge
|
||||
{
|
||||
friend class CartridgeCDFWidget;
|
||||
friend class CartridgeRamCDFWidget;
|
||||
|
||||
public:
|
||||
/**
|
||||
Create a new cartridge using the specified image
|
||||
|
||||
@param image Pointer to the ROM image
|
||||
@param size The size of the ROM image
|
||||
@param settings A reference to the various settings (read-only)
|
||||
*/
|
||||
CartridgeCDF(const uInt8* image, uInt32 size, const Settings& settings);
|
||||
|
||||
/**
|
||||
Destructor
|
||||
*/
|
||||
virtual ~CartridgeCDF();
|
||||
|
||||
public:
|
||||
/**
|
||||
Reset device to its power-on state
|
||||
*/
|
||||
void reset() override;
|
||||
|
||||
/**
|
||||
Notification method invoked by the system when the console type
|
||||
has changed. We need this to inform the Thumbulator that the
|
||||
timing has changed.
|
||||
|
||||
@param timing Enum representing the new console type
|
||||
*/
|
||||
void consoleChanged(ConsoleTiming timing) override;
|
||||
|
||||
/**
|
||||
Notification method invoked by the system right before the
|
||||
system resets its cycle counter to zero. It may be necessary
|
||||
to override this method for devices that remember cycle counts.
|
||||
*/
|
||||
void systemCyclesReset() override;
|
||||
|
||||
/**
|
||||
Install cartridge in the specified system. Invoked by the system
|
||||
when the cartridge is attached to it.
|
||||
|
||||
@param system The system the device should install itself in
|
||||
*/
|
||||
void install(System& system) override;
|
||||
|
||||
/**
|
||||
Install pages for the specified bank in the system.
|
||||
|
||||
@param bank The bank that should be installed in the system
|
||||
*/
|
||||
bool bank(uInt16 bank) override;
|
||||
|
||||
/**
|
||||
Get the current bank.
|
||||
*/
|
||||
uInt16 getBank() const override;
|
||||
|
||||
/**
|
||||
Query the number of banks supported by the cartridge.
|
||||
*/
|
||||
uInt16 bankCount() const override;
|
||||
|
||||
/**
|
||||
Patch the cartridge ROM.
|
||||
|
||||
@param address The ROM address to patch
|
||||
@param value The value to place into the address
|
||||
@return Success or failure of the patch operation
|
||||
*/
|
||||
bool patch(uInt16 address, uInt8 value) override;
|
||||
|
||||
/**
|
||||
Access the internal ROM image for this cartridge.
|
||||
|
||||
@param size Set to the size of the internal ROM image data
|
||||
@return A pointer to the internal ROM image data
|
||||
*/
|
||||
const uInt8* getImage(int& size) const override;
|
||||
|
||||
/**
|
||||
Save the current state of this cart to the given Serializer.
|
||||
|
||||
@param out The Serializer object to use
|
||||
@return False on any errors, else true
|
||||
*/
|
||||
bool save(Serializer& out) const override;
|
||||
|
||||
/**
|
||||
Load the current state of this cart from the given Serializer.
|
||||
|
||||
@param in The Serializer object to use
|
||||
@return False on any errors, else true
|
||||
*/
|
||||
bool load(Serializer& in) override;
|
||||
|
||||
/**
|
||||
Get a descriptor for the device name (used in error checking).
|
||||
|
||||
@return The name of the object
|
||||
*/
|
||||
string name() const override { return "CartridgeCDF"; }
|
||||
|
||||
// uInt8 busOverdrive(uInt16 address) override;
|
||||
|
||||
/**
|
||||
Used for Thumbulator to pass values back to the cartridge
|
||||
*/
|
||||
uInt32 thumbCallback(uInt8 function, uInt32 value1, uInt32 value2) override;
|
||||
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
/**
|
||||
Get debugger widget responsible for accessing the inner workings
|
||||
of the cart.
|
||||
*/
|
||||
CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont,
|
||||
const GUI::Font& nfont, int x, int y, int w, int h) override
|
||||
{
|
||||
return new CartridgeCDFWidget(boss, lfont, nfont, x, y, w, h, *this);
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
/**
|
||||
Get the byte at the specified address.
|
||||
|
||||
@return The byte at the specified address
|
||||
*/
|
||||
uInt8 peek(uInt16 address) override;
|
||||
|
||||
/**
|
||||
Change the byte at the specified address to the given value
|
||||
|
||||
@param address The address where the value should be stored
|
||||
@param value The value to be stored at the address
|
||||
@return True if the poke changed the device address space, else false
|
||||
*/
|
||||
bool poke(uInt16 address, uInt8 value) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
Sets the initial state of the DPC pointers and RAM
|
||||
*/
|
||||
void setInitialState();
|
||||
|
||||
/**
|
||||
Updates any data fetchers in music mode based on the number of
|
||||
CPU cycles which have passed since the last update.
|
||||
*/
|
||||
void updateMusicModeDataFetchers();
|
||||
|
||||
/**
|
||||
Call Special Functions
|
||||
*/
|
||||
void callFunction(uInt8 value);
|
||||
|
||||
uInt32 getDatastreamPointer(uInt8 index);
|
||||
void setDatastreamPointer(uInt8 index, uInt32 value);
|
||||
|
||||
uInt32 getDatastreamIncrement(uInt8 index);
|
||||
void setDatastreamIncrement(uInt8 index, uInt32 value);
|
||||
|
||||
uInt8 readFromDatastream(uInt8 index);
|
||||
|
||||
uInt32 getWaveform(uInt8 index);
|
||||
uInt32 getWaveformSize(uInt8 index);
|
||||
|
||||
private:
|
||||
// The 32K ROM image of the cartridge
|
||||
uInt8 myImage[32768];
|
||||
|
||||
// Pointer to the 28K program ROM image of the cartridge
|
||||
uInt8* myProgramImage;
|
||||
|
||||
// Pointer to the 4K display ROM image of the cartridge
|
||||
uInt8* myDisplayImage;
|
||||
|
||||
// Pointer to the 2K CDF driver image in RAM
|
||||
uInt8* myBusDriverImage;
|
||||
|
||||
// The CDF 8k RAM image, used as:
|
||||
// $0000 - 2K CDF driver
|
||||
// $0800 - 4K Display Data
|
||||
// $1800 - 2K C Variable & Stack
|
||||
uInt8 myCDFRAM[8192];
|
||||
|
||||
#ifdef THUMB_SUPPORT
|
||||
// Pointer to the Thumb ARM emulator object
|
||||
unique_ptr<Thumbulator> myThumbEmulator;
|
||||
#endif
|
||||
|
||||
// Indicates which bank is currently active
|
||||
uInt16 myCurrentBank;
|
||||
|
||||
// System cycle count when the last update to music data fetchers occurred
|
||||
Int32 mySystemCycles;
|
||||
|
||||
Int32 myARMCycles;
|
||||
|
||||
uInt8 mySetAddress;
|
||||
|
||||
// The music mode counters
|
||||
uInt32 myMusicCounters[3];
|
||||
|
||||
// The music frequency
|
||||
uInt32 myMusicFrequencies[3];
|
||||
|
||||
// The music waveform sizes
|
||||
uInt8 myMusicWaveformSize[3];
|
||||
|
||||
// Fractional DPC music OSC clocks unused during the last update
|
||||
double myFractionalClocks;
|
||||
|
||||
// Controls mode, lower nybble sets Fast Fetch, upper nybble sets audio
|
||||
// -0 = Fast Fetch ON
|
||||
// -F = Fast Fetch OFF
|
||||
// 0- = Packed Digital Sample
|
||||
// F- = 3 Voice Music
|
||||
uInt8 myMode;
|
||||
|
||||
// set to address of #value if last byte peeked was A9 (LDA #)
|
||||
uInt16 myLDAimmediateOperandAddress;
|
||||
|
||||
TIA* myTIA;
|
||||
|
||||
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
|
|
@ -61,7 +61,9 @@ CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size,
|
|||
myThumbEmulator = make_ptr<Thumbulator>
|
||||
(reinterpret_cast<uInt16*>(myProgramImage-0xC00),
|
||||
reinterpret_cast<uInt16*>(myDPCRAM),
|
||||
settings.getBool("thumb.trapfatal"));
|
||||
settings.getBool("thumb.trapfatal"),
|
||||
Thumbulator::ConfigureFor::DPCplus,
|
||||
this);
|
||||
#endif
|
||||
setInitialState();
|
||||
|
||||
|
@ -196,9 +198,10 @@ inline void CartridgeDPCPlus::callFunction(uInt8 value)
|
|||
myParameterPointer = 0;
|
||||
break;
|
||||
#ifdef THUMB_SUPPORT
|
||||
case 254:
|
||||
case 255:
|
||||
// Call user written ARM code (most likely be C compiled for ARM)
|
||||
case 254: // call with IRQ driven audio, no special handling needed at this
|
||||
// time for Stella as ARM code "runs in zero 6507 cycles".
|
||||
case 255: // call without IRQ driven audio
|
||||
try {
|
||||
Int32 cycles = mySystem->cycles() - myARMCycles;
|
||||
myARMCycles = mySystem->cycles();
|
||||
|
|
|
@ -54,11 +54,14 @@ using Common::Base;
|
|||
#endif
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Thumbulator::Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, bool traponfatal)
|
||||
Thumbulator::Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, bool traponfatal,
|
||||
Thumbulator::ConfigureFor configurefor, Cartridge* cartridge)
|
||||
: rom(rom_ptr),
|
||||
ram(ram_ptr),
|
||||
T1TCR(0),
|
||||
T1TC(0)
|
||||
T1TC(0),
|
||||
configuration(configurefor),
|
||||
myCartridge(cartridge)
|
||||
{
|
||||
setConsoleTiming(ConsoleTiming::ntsc);
|
||||
trapFatalErrors(traponfatal);
|
||||
|
@ -227,8 +230,29 @@ void Thumbulator::write16(uInt32 addr, uInt32 data)
|
|||
{
|
||||
if((addr > 0x40001fff) && (addr < 0x50000000))
|
||||
fatalError("write16", addr, "abort - out of range");
|
||||
else if((addr > 0x40000028) && (addr < 0x40000c00))
|
||||
|
||||
switch(configuration)
|
||||
{
|
||||
// this protects 2K Harmony/Melody Drivers
|
||||
// Initial section of driver is the bootstrap which copies the driver
|
||||
// from ROM to RAM, so it can safely be used by the custom ARM code
|
||||
// as additional RAM
|
||||
case ConfigureFor::BUS:
|
||||
case ConfigureFor::CDF:
|
||||
if((addr > 0x40000028) && (addr < 0x40000800))
|
||||
fatalError("write16", addr, "to bankswitch code area");
|
||||
break;
|
||||
|
||||
// this protects 3K Harmony/Melody Drivers
|
||||
// Initial section of driver is the bootstrap which copies the driver
|
||||
// from ROM to RAM, so it can safely be used by the custom ARM code
|
||||
// as additional RAM
|
||||
case ConfigureFor::DPCplus:
|
||||
if((addr > 0x40000028) && (addr < 0x40000c00))
|
||||
fatalError("write16", addr, "to bankswitch code area");
|
||||
break;
|
||||
}
|
||||
|
||||
if(addr & 1)
|
||||
fatalError("write16", addr, "abort - misaligned");
|
||||
|
||||
|
@ -1042,14 +1066,95 @@ int Thumbulator::execute()
|
|||
//fprintf(stderr,"bx r%u 0x%X 0x%X\n",rm,rc,pc);
|
||||
if(rc & 1)
|
||||
{
|
||||
// branch to odd address denotes 16 bit ARM code
|
||||
rc &= ~1;
|
||||
write_register(15, rc);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//fprintf(stderr,"cannot branch to arm 0x%08X 0x%04X\n",pc,inst);
|
||||
// fxq: or maybe this one??
|
||||
// branch to even address denotes 32 bit ARM code, which the Thumbulator
|
||||
// class does not support. So capture relavent information and hand it
|
||||
// off to the Cartridge class for it to handle.
|
||||
|
||||
bool handled = false;
|
||||
|
||||
switch(configuration)
|
||||
{
|
||||
case ConfigureFor::BUS:
|
||||
case ConfigureFor::CDF:
|
||||
// this subroutine interface is used in BUS and CDF drivers,
|
||||
// and starts at address 0x000006e0 in both.
|
||||
// _SetNote:
|
||||
// ldr r4, =NoteStore
|
||||
// bx r4 // bx instruction at 0x000006e2
|
||||
// _ResetWave:
|
||||
// ldr r4, =ResetWaveStore
|
||||
// bx r4 // bx instruction at 0x000006e6
|
||||
// _GetWavePtr:
|
||||
// ldr r4, =WavePtrFetch
|
||||
// bx r4 // bx instruction at 0x000006ea
|
||||
// _SetWaveSize:
|
||||
// ldr r4, =WaveSizeStore
|
||||
// bx r4 // bx instruction at 0x000006ee
|
||||
|
||||
// address to test for is + 4 due to pipelining
|
||||
#define BUS_SetNote (0x000006e2 + 4)
|
||||
#define BUS_ResetWave (0x000006e6 + 4)
|
||||
#define BUS_GetWavePtr (0x000006ea + 4)
|
||||
#define BUS_SetWaveSize (0x000006ee + 4)
|
||||
|
||||
if (pc == BUS_SetNote)
|
||||
{
|
||||
myCartridge->thumbCallback(0, read_register(2), read_register(3));
|
||||
handled = true;
|
||||
}
|
||||
else if (pc == BUS_ResetWave)
|
||||
{
|
||||
myCartridge->thumbCallback(1, read_register(2), 0);
|
||||
handled = true;
|
||||
}
|
||||
else if (pc == BUS_GetWavePtr)
|
||||
{
|
||||
write_register(2, myCartridge->thumbCallback(2, read_register(2), 0));
|
||||
handled = true;
|
||||
}
|
||||
else if (pc == BUS_SetWaveSize)
|
||||
{
|
||||
myCartridge->thumbCallback(3, read_register(2), read_register(3));
|
||||
handled = true;
|
||||
}
|
||||
else if (pc == 0x0000083a)
|
||||
{
|
||||
// exiting Custom ARM code, returning to BUS Driver control
|
||||
}
|
||||
else
|
||||
{
|
||||
// just for testing
|
||||
uInt32 r0 = read_register(0);
|
||||
uInt32 r1 = read_register(1);
|
||||
uInt32 r2 = read_register(2);
|
||||
uInt32 r3 = read_register(3);
|
||||
uInt32 r4 = read_register(4);
|
||||
myCartridge->thumbCallback(255,0,0);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ConfigureFor::DPCplus:
|
||||
// no 32-bit subroutines in DPC+
|
||||
break;
|
||||
}
|
||||
|
||||
if (handled)
|
||||
{
|
||||
rc = read_register(14); // lr
|
||||
rc += 2;
|
||||
rc &= ~1;
|
||||
write_register(15, rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -2098,8 +2203,22 @@ int Thumbulator::reset()
|
|||
{
|
||||
std::fill(reg_norm, reg_norm+12, 0);
|
||||
reg_norm[13] = 0x40001FB4;
|
||||
reg_norm[14] = 0x00000C00;
|
||||
reg_norm[15] = 0x00000C0B;
|
||||
|
||||
switch(configuration)
|
||||
{
|
||||
// future 2K Harmony/Melody drivers will most likely use these settings
|
||||
case ConfigureFor::BUS:
|
||||
case ConfigureFor::CDF:
|
||||
reg_norm[14] = 0x00000800; // Link Register
|
||||
reg_norm[15] = 0x0000080B; // Program Counter
|
||||
break;
|
||||
|
||||
// future 3K Harmony/Melody drivers will most likely use these settings
|
||||
case ConfigureFor::DPCplus:
|
||||
reg_norm[14] = 0x00000C00; // Link Register
|
||||
reg_norm[15] = 0x00000C0B; // Program Counter
|
||||
break;
|
||||
}
|
||||
|
||||
cpsr = mamcr = 0;
|
||||
handler_mode = false;
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#define THUMBULATOR_HXX
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "Cart.hxx"
|
||||
#include "Console.hxx"
|
||||
|
||||
#define ROMADDMASK 0x7FFF
|
||||
|
@ -44,7 +45,16 @@
|
|||
class Thumbulator
|
||||
{
|
||||
public:
|
||||
Thumbulator(const uInt16* rom, uInt16* ram, bool traponfatal);
|
||||
// control cartridge specific features of the Thumbulator class,
|
||||
// such as the start location for calling custom code
|
||||
enum ConfigureFor {
|
||||
BUS, // cartridges of type BUS
|
||||
CDF, // cartridges of type CDF
|
||||
DPCplus // cartridges of type DPC+
|
||||
};
|
||||
|
||||
Thumbulator(const uInt16* rom, uInt16* ram, bool traponfatal,
|
||||
Thumbulator::ConfigureFor configurefor, Cartridge* cartridge);
|
||||
|
||||
/**
|
||||
Run the ARM code, and return when finished. A runtime_error exception is
|
||||
|
@ -123,6 +133,10 @@ class Thumbulator
|
|||
|
||||
static bool trapOnFatal;
|
||||
|
||||
ConfigureFor configuration;
|
||||
|
||||
Cartridge* myCartridge;
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
Thumbulator() = delete;
|
||||
|
|
|
@ -214,6 +214,14 @@
|
|||
2D91751009BA90380026E9FF /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DEB3D4C0629BD24007EBBD3 /* OpenGL.framework */; };
|
||||
2D91751209BA90380026E9FF /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D17D98E08BC398400E47F69 /* ApplicationServices.framework */; };
|
||||
2DEFB40C09C3386F00754289 /* Cart.icns in Resources */ = {isa = PBXBuildFile; fileRef = 2DEFB40B09C3386F00754289 /* Cart.icns */; };
|
||||
CFE3F60B1E84A9A200A8204E /* CartBUSWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CFE3F6071E84A9A200A8204E /* CartBUSWidget.cxx */; };
|
||||
CFE3F60C1E84A9A200A8204E /* CartBUSWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = CFE3F6081E84A9A200A8204E /* CartBUSWidget.hxx */; };
|
||||
CFE3F60D1E84A9A200A8204E /* CartCDFWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CFE3F6091E84A9A200A8204E /* CartCDFWidget.cxx */; };
|
||||
CFE3F60E1E84A9A200A8204E /* CartCDFWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = CFE3F60A1E84A9A200A8204E /* CartCDFWidget.hxx */; };
|
||||
CFE3F6131E84A9CE00A8204E /* CartBUS.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CFE3F60F1E84A9CE00A8204E /* CartBUS.cxx */; };
|
||||
CFE3F6141E84A9CE00A8204E /* CartBUS.hxx in Headers */ = {isa = PBXBuildFile; fileRef = CFE3F6101E84A9CE00A8204E /* CartBUS.hxx */; };
|
||||
CFE3F6151E84A9CE00A8204E /* CartCDF.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CFE3F6111E84A9CE00A8204E /* CartCDF.cxx */; };
|
||||
CFE3F6161E84A9CE00A8204E /* CartCDF.hxx in Headers */ = {isa = PBXBuildFile; fileRef = CFE3F6121E84A9CE00A8204E /* CartCDF.hxx */; };
|
||||
DC047FEE1A4A6F3600348F0F /* JoystickDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC047FEC1A4A6F3600348F0F /* JoystickDialog.cxx */; };
|
||||
DC047FEF1A4A6F3600348F0F /* JoystickDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC047FED1A4A6F3600348F0F /* JoystickDialog.hxx */; };
|
||||
DC07A3C80CAD738A009B4BC9 /* StateManager.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC07A3C60CAD738A009B4BC9 /* StateManager.cxx */; };
|
||||
|
@ -830,6 +838,14 @@
|
|||
2DF971D70892CEA400F64D23 /* DebuggerSystem.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = DebuggerSystem.hxx; path = ../debugger/DebuggerSystem.hxx; sourceTree = SOURCE_ROOT; };
|
||||
2DF971DF0892CEA400F64D23 /* Expression.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = Expression.hxx; path = ../debugger/Expression.hxx; sourceTree = SOURCE_ROOT; };
|
||||
B2F367C504C7ADC700A80002 /* SDLMain.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; path = SDLMain.nib; sourceTree = "<group>"; };
|
||||
CFE3F6071E84A9A200A8204E /* CartBUSWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartBUSWidget.cxx; path = ../debugger/gui/CartBUSWidget.cxx; sourceTree = "<group>"; };
|
||||
CFE3F6081E84A9A200A8204E /* CartBUSWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartBUSWidget.hxx; path = ../debugger/gui/CartBUSWidget.hxx; sourceTree = "<group>"; };
|
||||
CFE3F6091E84A9A200A8204E /* CartCDFWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartCDFWidget.cxx; path = ../debugger/gui/CartCDFWidget.cxx; sourceTree = "<group>"; };
|
||||
CFE3F60A1E84A9A200A8204E /* CartCDFWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartCDFWidget.hxx; path = ../debugger/gui/CartCDFWidget.hxx; sourceTree = "<group>"; };
|
||||
CFE3F60F1E84A9CE00A8204E /* CartBUS.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartBUS.cxx; path = ../emucore/CartBUS.cxx; sourceTree = "<group>"; };
|
||||
CFE3F6101E84A9CE00A8204E /* CartBUS.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartBUS.hxx; path = ../emucore/CartBUS.hxx; sourceTree = "<group>"; };
|
||||
CFE3F6111E84A9CE00A8204E /* CartCDF.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CartCDF.cxx; path = ../emucore/CartCDF.cxx; sourceTree = "<group>"; };
|
||||
CFE3F6121E84A9CE00A8204E /* CartCDF.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CartCDF.hxx; path = ../emucore/CartCDF.hxx; sourceTree = "<group>"; };
|
||||
DC047FEC1A4A6F3600348F0F /* JoystickDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JoystickDialog.cxx; path = ../gui/JoystickDialog.cxx; sourceTree = "<group>"; };
|
||||
DC047FED1A4A6F3600348F0F /* JoystickDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = JoystickDialog.hxx; path = ../gui/JoystickDialog.hxx; sourceTree = "<group>"; };
|
||||
DC07A3C60CAD738A009B4BC9 /* StateManager.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = StateManager.cxx; path = ../emucore/StateManager.cxx; sourceTree = SOURCE_ROOT; };
|
||||
|
@ -1335,6 +1351,10 @@
|
|||
DCAACB07188D636F00A4D282 /* CartBFSCWidget.hxx */,
|
||||
DCAACB08188D636F00A4D282 /* CartBFWidget.cxx */,
|
||||
DCAACB09188D636F00A4D282 /* CartBFWidget.hxx */,
|
||||
CFE3F6071E84A9A200A8204E /* CartBUSWidget.cxx */,
|
||||
CFE3F6081E84A9A200A8204E /* CartBUSWidget.hxx */,
|
||||
CFE3F6091E84A9A200A8204E /* CartCDFWidget.cxx */,
|
||||
CFE3F60A1E84A9A200A8204E /* CartCDFWidget.hxx */,
|
||||
DC676A2B1729A0B000E4E73D /* CartCMWidget.cxx */,
|
||||
DC676A2C1729A0B000E4E73D /* CartCMWidget.hxx */,
|
||||
DC676A2D1729A0B000E4E73D /* CartCTYWidget.cxx */,
|
||||
|
@ -1545,6 +1565,10 @@
|
|||
DCAACAEF188D631500A4D282 /* CartBF.hxx */,
|
||||
DCAACAF0188D631500A4D282 /* CartBFSC.cxx */,
|
||||
DCAACAF1188D631500A4D282 /* CartBFSC.hxx */,
|
||||
CFE3F60F1E84A9CE00A8204E /* CartBUS.cxx */,
|
||||
CFE3F6101E84A9CE00A8204E /* CartBUS.hxx */,
|
||||
CFE3F6111E84A9CE00A8204E /* CartCDF.cxx */,
|
||||
CFE3F6121E84A9CE00A8204E /* CartCDF.hxx */,
|
||||
DC8C1BA714B25DE7006440EE /* CartCM.cxx */,
|
||||
DC8C1BA814B25DE7006440EE /* CartCM.hxx */,
|
||||
DC6727081556F4860023653B /* CartCTY.cxx */,
|
||||
|
@ -2134,6 +2158,7 @@
|
|||
DC3EE8661E2C0E6D00905161 /* inflate.h in Headers */,
|
||||
DCC527D510B9DA19005E1287 /* NullDev.hxx in Headers */,
|
||||
DCC527D710B9DA19005E1287 /* System.hxx in Headers */,
|
||||
CFE3F6161E84A9CE00A8204E /* CartCDF.hxx in Headers */,
|
||||
DCC527DB10B9DA6A005E1287 /* bspf.hxx in Headers */,
|
||||
DC6B2BA511037FF200F199A7 /* CartDebug.hxx in Headers */,
|
||||
DC6B2BA711037FF200F199A7 /* DiStella.hxx in Headers */,
|
||||
|
@ -2144,6 +2169,7 @@
|
|||
DCF3A6F41DFC75E3008A8AF3 /* LatchedInput.hxx in Headers */,
|
||||
DC74E5C7198AF12700F37E36 /* CartDASHWidget.hxx in Headers */,
|
||||
DCD6FC7711C281ED005DA767 /* pngpriv.h in Headers */,
|
||||
CFE3F60C1E84A9A200A8204E /* CartBUSWidget.hxx in Headers */,
|
||||
DCD6FC9411C28C6F005DA767 /* PNGLibrary.hxx in Headers */,
|
||||
DC98F35711F5B56200AA520F /* MessageBox.hxx in Headers */,
|
||||
DCFFE59E12100E1400DFA000 /* ComboDialog.hxx in Headers */,
|
||||
|
@ -2200,6 +2226,7 @@
|
|||
DCAAE5F31715887B0080BB82 /* CartUAWidget.hxx in Headers */,
|
||||
DC676A421729A0B000E4E73D /* Cart3EWidget.hxx in Headers */,
|
||||
DC676A441729A0B000E4E73D /* Cart4A50Widget.hxx in Headers */,
|
||||
CFE3F6141E84A9CE00A8204E /* CartBUS.hxx in Headers */,
|
||||
DC676A461729A0B000E4E73D /* CartARWidget.hxx in Headers */,
|
||||
DC676A481729A0B000E4E73D /* CartCMWidget.hxx in Headers */,
|
||||
DC676A4A1729A0B000E4E73D /* CartCTYWidget.hxx in Headers */,
|
||||
|
@ -2241,6 +2268,7 @@
|
|||
DCF3A6F91DFC75E3008A8AF3 /* PaddleReader.hxx in Headers */,
|
||||
DCFF14CE18B0260300A20364 /* EventHandlerSDL2.hxx in Headers */,
|
||||
DC047FEF1A4A6F3600348F0F /* JoystickDialog.hxx in Headers */,
|
||||
CFE3F60E1E84A9A200A8204E /* CartCDFWidget.hxx in Headers */,
|
||||
DCF3A6F01DFC75E3008A8AF3 /* DrawCounterDecodes.hxx in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -2391,6 +2419,7 @@
|
|||
2D9174B509BA90380026E9FF /* ListWidget.cxx in Sources */,
|
||||
2D9174B609BA90380026E9FF /* Menu.cxx in Sources */,
|
||||
DC5E473B19EC9A14000E45DF /* EventJoyHandler.cxx in Sources */,
|
||||
CFE3F60D1E84A9A200A8204E /* CartCDFWidget.cxx in Sources */,
|
||||
DC1B2EC71E50036100F62837 /* TrakBall.cxx in Sources */,
|
||||
2D9174B709BA90380026E9FF /* OptionsDialog.cxx in Sources */,
|
||||
2D9174B809BA90380026E9FF /* PopUpWidget.cxx in Sources */,
|
||||
|
@ -2404,6 +2433,7 @@
|
|||
2D9174BD09BA90380026E9FF /* Widget.cxx in Sources */,
|
||||
2D9174BE09BA90380026E9FF /* CartUA.cxx in Sources */,
|
||||
DC3EE86E1E2C0E6D00905161 /* zutil.c in Sources */,
|
||||
CFE3F60B1E84A9A200A8204E /* CartBUSWidget.cxx in Sources */,
|
||||
DC1B2EC51E50036100F62837 /* AtariMouse.cxx in Sources */,
|
||||
2D9174BF09BA90380026E9FF /* FSNode.cxx in Sources */,
|
||||
DCF3A6FE1DFC75E3008A8AF3 /* TIA.cxx in Sources */,
|
||||
|
@ -2448,6 +2478,7 @@
|
|||
2D91750309BA90380026E9FF /* TogglePixelWidget.cxx in Sources */,
|
||||
2D91750409BA90380026E9FF /* ToggleWidget.cxx in Sources */,
|
||||
2D91750609BA90380026E9FF /* TiaZoomWidget.cxx in Sources */,
|
||||
CFE3F6131E84A9CE00A8204E /* CartBUS.cxx in Sources */,
|
||||
DC73BD851915E5B1003FAFAD /* FBSurfaceSDL2.cxx in Sources */,
|
||||
2D91750709BA90380026E9FF /* TIASnd.cxx in Sources */,
|
||||
2D91750809BA90380026E9FF /* AudioWidget.cxx in Sources */,
|
||||
|
@ -2496,6 +2527,7 @@
|
|||
DC6B2BA411037FF200F199A7 /* CartDebug.cxx in Sources */,
|
||||
DCB20EC71A0C506C0048F595 /* main.cxx in Sources */,
|
||||
DC6B2BA611037FF200F199A7 /* DiStella.cxx in Sources */,
|
||||
CFE3F6151E84A9CE00A8204E /* CartCDF.cxx in Sources */,
|
||||
DCD3F7C511340AAF00DBA3AE /* Genesis.cxx in Sources */,
|
||||
DCAD60A81152F8BD00BC4184 /* CartDPCPlus.cxx in Sources */,
|
||||
DCD6FC7011C281ED005DA767 /* png.c in Sources */,
|
||||
|
|
Loading…
Reference in New Issue