Merge pull request #110 from SpiceWare/master

Preliminary support for BUS and CDF
This commit is contained in:
sa666666 2017-03-24 16:09:59 -02:30 committed by GitHub
commit 7c6821dfcb
16 changed files with 3136 additions and 13 deletions

View File

@ -74,6 +74,12 @@ string Base::toString(int value, Common::Base::Format outputBase)
case Base::F_16_2: // base 16: 2 bytes wide case Base::F_16_2: // base 16: 2 bytes wide
std::snprintf(vToS_buf, 3, myFmt[1], value); std::snprintf(vToS_buf, 3, myFmt[1], value);
break; 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 case Base::F_16_4: // base 16: 4 bytes wide
std::snprintf(vToS_buf, 5, myFmt[2], value); std::snprintf(vToS_buf, 5, myFmt[2], value);
break; break;

View File

@ -42,6 +42,8 @@ class Base
F_16, // base 16: 2, 4, 8 bytes (depending on value) F_16, // base 16: 2, 4, 8 bytes (depending on value)
F_16_1, // base 16: 1 byte wide F_16_1, // base 16: 1 byte wide
F_16_2, // base 16: 2 bytes 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_4, // base 16: 4 bytes wide
F_16_8, // base 16: 8 bytes wide F_16_8, // base 16: 8 bytes wide
F_10, // base 10: 3 or 5 bytes (depending on value) F_10, // base 10: 3 or 5 bytes (depending on value)

View File

@ -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];
}

View File

@ -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

View File

@ -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];
}

View File

@ -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

View File

@ -26,6 +26,8 @@
#include "Cart4K.hxx" #include "Cart4K.hxx"
#include "Cart4KSC.hxx" #include "Cart4KSC.hxx"
#include "CartAR.hxx" #include "CartAR.hxx"
#include "CartBUS.hxx"
#include "CartCDF.hxx"
#include "CartCM.hxx" #include "CartCM.hxx"
#include "CartCTY.hxx" #include "CartCTY.hxx"
#include "CartCV.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); cartridge = make_ptr<Cartridge4KSC>(image, size, settings);
else if(type == "AR") else if(type == "AR")
cartridge = make_ptr<CartridgeAR>(image, size, settings); 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") else if(type == "CM")
cartridge = make_ptr<CartridgeCM>(image, size, settings); cartridge = make_ptr<CartridgeCM>(image, size, settings);
else if(type == "CTY") else if(type == "CTY")
@ -472,6 +478,10 @@ string Cartridge::autodetectType(const uInt8* image, uInt32 size)
type = "3E"; type = "3E";
else if(isProbably3F(image, size)) else if(isProbably3F(image, size))
type = "3F"; type = "3F";
else if (isProbablyBUS(image, size))
type = "BUS";
else if (isProbablyCDF(image, size))
type = "CDF";
else if(isProbablyDPCplus(image, size)) else if(isProbablyDPCplus(image, size))
type = "DPC+"; type = "DPC+";
else if(isProbablyCTY(image, size)) 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) bool Cartridge::isProbablyDPCplus(const uInt8* image, uInt32 size)
{ {
// DPC+ ARM code has 2 occurrences of the string DPC+ // 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', '+' }; uInt8 signature[] = { 'D', 'P', 'C', '+' };
return searchForBytes(image, size, signature, 4, 2); return searchForBytes(image, size, signature, 4, 2);
} }
@ -858,6 +870,26 @@ bool Cartridge::isProbablyBF(const uInt8* image, uInt32 size, const char*& type)
return false; 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) bool Cartridge::isProbablyDF(const uInt8* image, uInt32 size, const char*& type)
{ {
@ -997,6 +1029,8 @@ Cartridge::BankswitchType Cartridge::ourBSList[ourNumBSTypes] = {
{ "AR", "AR (Supercharger)" }, { "AR", "AR (Supercharger)" },
{ "BF", "BF (CPUWIZ 256K)" }, { "BF", "BF (CPUWIZ 256K)" },
{ "BFSC", "BFSC (CPUWIZ 256K + ram)" }, { "BFSC", "BFSC (CPUWIZ 256K + ram)" },
{ "BUS", "BUS (Bus Stuffing)" },
{ "CDF", "CDF (Chris, Darrell, Fred)" },
{ "CM", "CM (SpectraVideo CompuMate)" }, { "CM", "CM (SpectraVideo CompuMate)" },
{ "CTY", "CTY (CDW - Chetiry)" }, { "CTY", "CTY (CDW - Chetiry)" },
{ "CV", "CV (Commavid extra ram)" }, { "CV", "CV (Commavid extra ram)" },

View File

@ -172,6 +172,13 @@ class Cartridge : public Device
*/ */
virtual void setRomName(const string& name) { } 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 Get debugger widget responsible for accessing the inner workings
of the cart. This will need to be overridden and implemented by 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* type;
const char* desc; const char* desc;
}; };
enum { ourNumBSTypes = 48 }; enum { ourNumBSTypes = 50 };
static BankswitchType ourBSList[ourNumBSTypes]; static BankswitchType ourBSList[ourNumBSTypes];
protected: protected:
@ -303,6 +310,16 @@ class Cartridge : public Device
*/ */
static bool isProbablyBF(const uInt8* image, uInt32 size, const char*& type); 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 Returns true if the image is probably a CTY bankswitching cartridge
*/ */

750
src/emucore/CartBUS.cxx Normal file
View File

@ -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;
}

287
src/emucore/CartBUS.hxx Normal file
View File

@ -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

659
src/emucore/CartCDF.cxx Executable file
View File

@ -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;
}

285
src/emucore/CartCDF.hxx Executable file
View File

@ -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

View File

@ -61,7 +61,9 @@ CartridgeDPCPlus::CartridgeDPCPlus(const uInt8* image, uInt32 size,
myThumbEmulator = make_ptr<Thumbulator> myThumbEmulator = make_ptr<Thumbulator>
(reinterpret_cast<uInt16*>(myProgramImage-0xC00), (reinterpret_cast<uInt16*>(myProgramImage-0xC00),
reinterpret_cast<uInt16*>(myDPCRAM), reinterpret_cast<uInt16*>(myDPCRAM),
settings.getBool("thumb.trapfatal")); settings.getBool("thumb.trapfatal"),
Thumbulator::ConfigureFor::DPCplus,
this);
#endif #endif
setInitialState(); setInitialState();
@ -196,9 +198,10 @@ inline void CartridgeDPCPlus::callFunction(uInt8 value)
myParameterPointer = 0; myParameterPointer = 0;
break; break;
#ifdef THUMB_SUPPORT #ifdef THUMB_SUPPORT
case 254:
case 255:
// Call user written ARM code (most likely be C compiled for ARM) // 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 { try {
Int32 cycles = mySystem->cycles() - myARMCycles; Int32 cycles = mySystem->cycles() - myARMCycles;
myARMCycles = mySystem->cycles(); myARMCycles = mySystem->cycles();

View File

@ -54,11 +54,14 @@ using Common::Base;
#endif #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), : rom(rom_ptr),
ram(ram_ptr), ram(ram_ptr),
T1TCR(0), T1TCR(0),
T1TC(0) T1TC(0),
configuration(configurefor),
myCartridge(cartridge)
{ {
setConsoleTiming(ConsoleTiming::ntsc); setConsoleTiming(ConsoleTiming::ntsc);
trapFatalErrors(traponfatal); trapFatalErrors(traponfatal);
@ -227,8 +230,29 @@ void Thumbulator::write16(uInt32 addr, uInt32 data)
{ {
if((addr > 0x40001fff) && (addr < 0x50000000)) if((addr > 0x40001fff) && (addr < 0x50000000))
fatalError("write16", addr, "abort - out of range"); fatalError("write16", addr, "abort - out of range");
else if((addr > 0x40000028) && (addr < 0x40000c00))
fatalError("write16", addr, "to bankswitch code area"); 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) if(addr & 1)
fatalError("write16", addr, "abort - misaligned"); 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); //fprintf(stderr,"bx r%u 0x%X 0x%X\n",rm,rc,pc);
if(rc & 1) if(rc & 1)
{ {
// branch to odd address denotes 16 bit ARM code
rc &= ~1; rc &= ~1;
write_register(15, rc); write_register(15, rc);
return 0; return 0;
} }
else else
{ {
//fprintf(stderr,"cannot branch to arm 0x%08X 0x%04X\n",pc,inst); // branch to even address denotes 32 bit ARM code, which the Thumbulator
// fxq: or maybe this one?? // 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; return 1;
} }
} }
@ -2098,9 +2203,23 @@ int Thumbulator::reset()
{ {
std::fill(reg_norm, reg_norm+12, 0); std::fill(reg_norm, reg_norm+12, 0);
reg_norm[13] = 0x40001FB4; 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; cpsr = mamcr = 0;
handler_mode = false; handler_mode = false;

View File

@ -28,6 +28,7 @@
#define THUMBULATOR_HXX #define THUMBULATOR_HXX
#include "bspf.hxx" #include "bspf.hxx"
#include "Cart.hxx"
#include "Console.hxx" #include "Console.hxx"
#define ROMADDMASK 0x7FFF #define ROMADDMASK 0x7FFF
@ -44,7 +45,16 @@
class Thumbulator class Thumbulator
{ {
public: 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 Run the ARM code, and return when finished. A runtime_error exception is
@ -122,6 +132,10 @@ class Thumbulator
ostringstream statusMsg; ostringstream statusMsg;
static bool trapOnFatal; static bool trapOnFatal;
ConfigureFor configuration;
Cartridge* myCartridge;
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported

View File

@ -214,6 +214,14 @@
2D91751009BA90380026E9FF /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DEB3D4C0629BD24007EBBD3 /* OpenGL.framework */; }; 2D91751009BA90380026E9FF /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DEB3D4C0629BD24007EBBD3 /* OpenGL.framework */; };
2D91751209BA90380026E9FF /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D17D98E08BC398400E47F69 /* ApplicationServices.framework */; }; 2D91751209BA90380026E9FF /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D17D98E08BC398400E47F69 /* ApplicationServices.framework */; };
2DEFB40C09C3386F00754289 /* Cart.icns in Resources */ = {isa = PBXBuildFile; fileRef = 2DEFB40B09C3386F00754289 /* Cart.icns */; }; 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 */; }; DC047FEE1A4A6F3600348F0F /* JoystickDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC047FEC1A4A6F3600348F0F /* JoystickDialog.cxx */; };
DC047FEF1A4A6F3600348F0F /* JoystickDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC047FED1A4A6F3600348F0F /* JoystickDialog.hxx */; }; DC047FEF1A4A6F3600348F0F /* JoystickDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC047FED1A4A6F3600348F0F /* JoystickDialog.hxx */; };
DC07A3C80CAD738A009B4BC9 /* StateManager.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC07A3C60CAD738A009B4BC9 /* StateManager.cxx */; }; 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; }; 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; }; 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>"; }; 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>"; }; 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>"; }; 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; }; 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 */, DCAACB07188D636F00A4D282 /* CartBFSCWidget.hxx */,
DCAACB08188D636F00A4D282 /* CartBFWidget.cxx */, DCAACB08188D636F00A4D282 /* CartBFWidget.cxx */,
DCAACB09188D636F00A4D282 /* CartBFWidget.hxx */, DCAACB09188D636F00A4D282 /* CartBFWidget.hxx */,
CFE3F6071E84A9A200A8204E /* CartBUSWidget.cxx */,
CFE3F6081E84A9A200A8204E /* CartBUSWidget.hxx */,
CFE3F6091E84A9A200A8204E /* CartCDFWidget.cxx */,
CFE3F60A1E84A9A200A8204E /* CartCDFWidget.hxx */,
DC676A2B1729A0B000E4E73D /* CartCMWidget.cxx */, DC676A2B1729A0B000E4E73D /* CartCMWidget.cxx */,
DC676A2C1729A0B000E4E73D /* CartCMWidget.hxx */, DC676A2C1729A0B000E4E73D /* CartCMWidget.hxx */,
DC676A2D1729A0B000E4E73D /* CartCTYWidget.cxx */, DC676A2D1729A0B000E4E73D /* CartCTYWidget.cxx */,
@ -1545,6 +1565,10 @@
DCAACAEF188D631500A4D282 /* CartBF.hxx */, DCAACAEF188D631500A4D282 /* CartBF.hxx */,
DCAACAF0188D631500A4D282 /* CartBFSC.cxx */, DCAACAF0188D631500A4D282 /* CartBFSC.cxx */,
DCAACAF1188D631500A4D282 /* CartBFSC.hxx */, DCAACAF1188D631500A4D282 /* CartBFSC.hxx */,
CFE3F60F1E84A9CE00A8204E /* CartBUS.cxx */,
CFE3F6101E84A9CE00A8204E /* CartBUS.hxx */,
CFE3F6111E84A9CE00A8204E /* CartCDF.cxx */,
CFE3F6121E84A9CE00A8204E /* CartCDF.hxx */,
DC8C1BA714B25DE7006440EE /* CartCM.cxx */, DC8C1BA714B25DE7006440EE /* CartCM.cxx */,
DC8C1BA814B25DE7006440EE /* CartCM.hxx */, DC8C1BA814B25DE7006440EE /* CartCM.hxx */,
DC6727081556F4860023653B /* CartCTY.cxx */, DC6727081556F4860023653B /* CartCTY.cxx */,
@ -2134,6 +2158,7 @@
DC3EE8661E2C0E6D00905161 /* inflate.h in Headers */, DC3EE8661E2C0E6D00905161 /* inflate.h in Headers */,
DCC527D510B9DA19005E1287 /* NullDev.hxx in Headers */, DCC527D510B9DA19005E1287 /* NullDev.hxx in Headers */,
DCC527D710B9DA19005E1287 /* System.hxx in Headers */, DCC527D710B9DA19005E1287 /* System.hxx in Headers */,
CFE3F6161E84A9CE00A8204E /* CartCDF.hxx in Headers */,
DCC527DB10B9DA6A005E1287 /* bspf.hxx in Headers */, DCC527DB10B9DA6A005E1287 /* bspf.hxx in Headers */,
DC6B2BA511037FF200F199A7 /* CartDebug.hxx in Headers */, DC6B2BA511037FF200F199A7 /* CartDebug.hxx in Headers */,
DC6B2BA711037FF200F199A7 /* DiStella.hxx in Headers */, DC6B2BA711037FF200F199A7 /* DiStella.hxx in Headers */,
@ -2144,6 +2169,7 @@
DCF3A6F41DFC75E3008A8AF3 /* LatchedInput.hxx in Headers */, DCF3A6F41DFC75E3008A8AF3 /* LatchedInput.hxx in Headers */,
DC74E5C7198AF12700F37E36 /* CartDASHWidget.hxx in Headers */, DC74E5C7198AF12700F37E36 /* CartDASHWidget.hxx in Headers */,
DCD6FC7711C281ED005DA767 /* pngpriv.h in Headers */, DCD6FC7711C281ED005DA767 /* pngpriv.h in Headers */,
CFE3F60C1E84A9A200A8204E /* CartBUSWidget.hxx in Headers */,
DCD6FC9411C28C6F005DA767 /* PNGLibrary.hxx in Headers */, DCD6FC9411C28C6F005DA767 /* PNGLibrary.hxx in Headers */,
DC98F35711F5B56200AA520F /* MessageBox.hxx in Headers */, DC98F35711F5B56200AA520F /* MessageBox.hxx in Headers */,
DCFFE59E12100E1400DFA000 /* ComboDialog.hxx in Headers */, DCFFE59E12100E1400DFA000 /* ComboDialog.hxx in Headers */,
@ -2200,6 +2226,7 @@
DCAAE5F31715887B0080BB82 /* CartUAWidget.hxx in Headers */, DCAAE5F31715887B0080BB82 /* CartUAWidget.hxx in Headers */,
DC676A421729A0B000E4E73D /* Cart3EWidget.hxx in Headers */, DC676A421729A0B000E4E73D /* Cart3EWidget.hxx in Headers */,
DC676A441729A0B000E4E73D /* Cart4A50Widget.hxx in Headers */, DC676A441729A0B000E4E73D /* Cart4A50Widget.hxx in Headers */,
CFE3F6141E84A9CE00A8204E /* CartBUS.hxx in Headers */,
DC676A461729A0B000E4E73D /* CartARWidget.hxx in Headers */, DC676A461729A0B000E4E73D /* CartARWidget.hxx in Headers */,
DC676A481729A0B000E4E73D /* CartCMWidget.hxx in Headers */, DC676A481729A0B000E4E73D /* CartCMWidget.hxx in Headers */,
DC676A4A1729A0B000E4E73D /* CartCTYWidget.hxx in Headers */, DC676A4A1729A0B000E4E73D /* CartCTYWidget.hxx in Headers */,
@ -2241,6 +2268,7 @@
DCF3A6F91DFC75E3008A8AF3 /* PaddleReader.hxx in Headers */, DCF3A6F91DFC75E3008A8AF3 /* PaddleReader.hxx in Headers */,
DCFF14CE18B0260300A20364 /* EventHandlerSDL2.hxx in Headers */, DCFF14CE18B0260300A20364 /* EventHandlerSDL2.hxx in Headers */,
DC047FEF1A4A6F3600348F0F /* JoystickDialog.hxx in Headers */, DC047FEF1A4A6F3600348F0F /* JoystickDialog.hxx in Headers */,
CFE3F60E1E84A9A200A8204E /* CartCDFWidget.hxx in Headers */,
DCF3A6F01DFC75E3008A8AF3 /* DrawCounterDecodes.hxx in Headers */, DCF3A6F01DFC75E3008A8AF3 /* DrawCounterDecodes.hxx in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -2391,6 +2419,7 @@
2D9174B509BA90380026E9FF /* ListWidget.cxx in Sources */, 2D9174B509BA90380026E9FF /* ListWidget.cxx in Sources */,
2D9174B609BA90380026E9FF /* Menu.cxx in Sources */, 2D9174B609BA90380026E9FF /* Menu.cxx in Sources */,
DC5E473B19EC9A14000E45DF /* EventJoyHandler.cxx in Sources */, DC5E473B19EC9A14000E45DF /* EventJoyHandler.cxx in Sources */,
CFE3F60D1E84A9A200A8204E /* CartCDFWidget.cxx in Sources */,
DC1B2EC71E50036100F62837 /* TrakBall.cxx in Sources */, DC1B2EC71E50036100F62837 /* TrakBall.cxx in Sources */,
2D9174B709BA90380026E9FF /* OptionsDialog.cxx in Sources */, 2D9174B709BA90380026E9FF /* OptionsDialog.cxx in Sources */,
2D9174B809BA90380026E9FF /* PopUpWidget.cxx in Sources */, 2D9174B809BA90380026E9FF /* PopUpWidget.cxx in Sources */,
@ -2404,6 +2433,7 @@
2D9174BD09BA90380026E9FF /* Widget.cxx in Sources */, 2D9174BD09BA90380026E9FF /* Widget.cxx in Sources */,
2D9174BE09BA90380026E9FF /* CartUA.cxx in Sources */, 2D9174BE09BA90380026E9FF /* CartUA.cxx in Sources */,
DC3EE86E1E2C0E6D00905161 /* zutil.c in Sources */, DC3EE86E1E2C0E6D00905161 /* zutil.c in Sources */,
CFE3F60B1E84A9A200A8204E /* CartBUSWidget.cxx in Sources */,
DC1B2EC51E50036100F62837 /* AtariMouse.cxx in Sources */, DC1B2EC51E50036100F62837 /* AtariMouse.cxx in Sources */,
2D9174BF09BA90380026E9FF /* FSNode.cxx in Sources */, 2D9174BF09BA90380026E9FF /* FSNode.cxx in Sources */,
DCF3A6FE1DFC75E3008A8AF3 /* TIA.cxx in Sources */, DCF3A6FE1DFC75E3008A8AF3 /* TIA.cxx in Sources */,
@ -2448,6 +2478,7 @@
2D91750309BA90380026E9FF /* TogglePixelWidget.cxx in Sources */, 2D91750309BA90380026E9FF /* TogglePixelWidget.cxx in Sources */,
2D91750409BA90380026E9FF /* ToggleWidget.cxx in Sources */, 2D91750409BA90380026E9FF /* ToggleWidget.cxx in Sources */,
2D91750609BA90380026E9FF /* TiaZoomWidget.cxx in Sources */, 2D91750609BA90380026E9FF /* TiaZoomWidget.cxx in Sources */,
CFE3F6131E84A9CE00A8204E /* CartBUS.cxx in Sources */,
DC73BD851915E5B1003FAFAD /* FBSurfaceSDL2.cxx in Sources */, DC73BD851915E5B1003FAFAD /* FBSurfaceSDL2.cxx in Sources */,
2D91750709BA90380026E9FF /* TIASnd.cxx in Sources */, 2D91750709BA90380026E9FF /* TIASnd.cxx in Sources */,
2D91750809BA90380026E9FF /* AudioWidget.cxx in Sources */, 2D91750809BA90380026E9FF /* AudioWidget.cxx in Sources */,
@ -2496,6 +2527,7 @@
DC6B2BA411037FF200F199A7 /* CartDebug.cxx in Sources */, DC6B2BA411037FF200F199A7 /* CartDebug.cxx in Sources */,
DCB20EC71A0C506C0048F595 /* main.cxx in Sources */, DCB20EC71A0C506C0048F595 /* main.cxx in Sources */,
DC6B2BA611037FF200F199A7 /* DiStella.cxx in Sources */, DC6B2BA611037FF200F199A7 /* DiStella.cxx in Sources */,
CFE3F6151E84A9CE00A8204E /* CartCDF.cxx in Sources */,
DCD3F7C511340AAF00DBA3AE /* Genesis.cxx in Sources */, DCD3F7C511340AAF00DBA3AE /* Genesis.cxx in Sources */,
DCAD60A81152F8BD00BC4184 /* CartDPCPlus.cxx in Sources */, DCAD60A81152F8BD00BC4184 /* CartDPCPlus.cxx in Sources */,
DCD6FC7011C281ED005DA767 /* png.c in Sources */, DCD6FC7011C281ED005DA767 /* png.c in Sources */,