mirror of https://github.com/stella-emu/stella.git
394 lines
14 KiB
C++
394 lines
14 KiB
C++
//============================================================================
|
|
//
|
|
// 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-2020 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.
|
|
//============================================================================
|
|
|
|
#include "CartDPCPlus.hxx"
|
|
#include "DataGridWidget.hxx"
|
|
#include "PopUpWidget.hxx"
|
|
#include "CartDPCPlusWidget.hxx"
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
CartridgeDPCPlusWidget::CartridgeDPCPlusWidget(
|
|
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont,
|
|
int x, int y, int w, int h, CartridgeDPCPlus& cart)
|
|
: CartDebugWidget(boss, lfont, nfont, x, y, w, h),
|
|
myCart{cart}
|
|
{
|
|
size_t size = cart.mySize;
|
|
|
|
ostringstream info;
|
|
info << "Extended DPC cartridge, six 4K banks, 4K display bank, 1K frequency table, "
|
|
<< "8K DPC RAM\n"
|
|
<< "DPC registers accessible @ $F000 - $F07F\n"
|
|
<< " $F000 - $F03F (R), $F040 - $F07F (W)\n"
|
|
<< "Banks accessible at hotspots $FFF6 to $FFFB\n"
|
|
<< "Startup bank = " << cart.startBank() << "\n"
|
|
<< "Ver = " << cart.myDriverMD5;
|
|
|
|
#if 0
|
|
// Eventually, we should query this from the debugger/disassembler
|
|
for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF6; i < 6; ++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 = 2,
|
|
ypos = addBaseInformation(size, "Activision (Pitfall II)", info.str()) +
|
|
myLineHeight;
|
|
|
|
VariantList items;
|
|
VarList::push_back(items, "0 ($FFF6)");
|
|
VarList::push_back(items, "1 ($FFF7)");
|
|
VarList::push_back(items, "2 ($FFF8)");
|
|
VarList::push_back(items, "3 ($FFF9)");
|
|
VarList::push_back(items, "4 ($FFFA)");
|
|
VarList::push_back(items, "5 ($FFFB)");
|
|
myBank =
|
|
new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx)"),
|
|
myLineHeight, items, "Set bank ",
|
|
0, kBankChanged);
|
|
myBank->setTarget(this);
|
|
addFocusWidget(myBank);
|
|
|
|
// Top registers
|
|
int lwidth = _font.getStringWidth("Counter Registers ");
|
|
xpos = 2; ypos += myLineHeight + 8;
|
|
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
|
myFontHeight, "Top Registers ", TextAlign::Left);
|
|
xpos += lwidth;
|
|
|
|
myTops = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::Fmt::_16);
|
|
myTops->setTarget(this);
|
|
myTops->setEditable(false);
|
|
|
|
// Bottom registers
|
|
xpos = 2; ypos += myLineHeight + 4;
|
|
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
|
myFontHeight, "Bottom Registers ", TextAlign::Left);
|
|
xpos += lwidth;
|
|
|
|
myBottoms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::Fmt::_16);
|
|
myBottoms->setTarget(this);
|
|
myBottoms->setEditable(false);
|
|
|
|
// Counter registers
|
|
xpos = 2; ypos += myLineHeight + 4;
|
|
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
|
myFontHeight, "Counter Registers ", TextAlign::Left);
|
|
xpos += lwidth;
|
|
|
|
myCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 4, 16, Common::Base::Fmt::_16_4);
|
|
myCounters->setTarget(this);
|
|
myCounters->setEditable(false);
|
|
|
|
// Fractional counter registers
|
|
xpos = 2; ypos += myLineHeight + 4;
|
|
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
|
myFontHeight, "Frac Counters ", TextAlign::Left);
|
|
xpos += lwidth;
|
|
|
|
myFracCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 4, 2, 8, 32, Common::Base::Fmt::_16_8);
|
|
myFracCounters->setTarget(this);
|
|
myFracCounters->setEditable(false);
|
|
|
|
// Fractional increment registers
|
|
xpos = 2; ypos += myFracCounters->getHeight() + 8;
|
|
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
|
myFontHeight, "Frac Increments ", TextAlign::Left);
|
|
xpos += lwidth;
|
|
|
|
myFracIncrements = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::Fmt::_16);
|
|
myFracIncrements->setTarget(this);
|
|
myFracIncrements->setEditable(false);
|
|
|
|
// Special function parameters
|
|
xpos = 2; ypos += myLineHeight + 4;
|
|
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
|
myFontHeight, "Function Params ", TextAlign::Left);
|
|
xpos += lwidth;
|
|
|
|
myParameter = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::Fmt::_16);
|
|
myParameter->setTarget(this);
|
|
myParameter->setEditable(false);
|
|
|
|
// Music counters
|
|
xpos = 2; ypos += myLineHeight + 4;
|
|
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
|
myFontHeight, "Music Counters ", TextAlign::Left);
|
|
xpos += lwidth;
|
|
|
|
myMusicCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::Fmt::_16_8);
|
|
myMusicCounters->setTarget(this);
|
|
myMusicCounters->setEditable(false);
|
|
|
|
// Music frequencies
|
|
xpos = 2; ypos += myLineHeight + 4;
|
|
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
|
myFontHeight, "Music Frequencies ", TextAlign::Left);
|
|
xpos += lwidth;
|
|
|
|
myMusicFrequencies = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::Fmt::_16_8);
|
|
myMusicFrequencies->setTarget(this);
|
|
myMusicFrequencies->setEditable(false);
|
|
|
|
// Music waveforms
|
|
xpos = 2; ypos += myLineHeight + 4;
|
|
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
|
myFontHeight, "Music Waveforms ", TextAlign::Left);
|
|
xpos += lwidth;
|
|
|
|
myMusicWaveforms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 4, 16, Common::Base::Fmt::_16_4);
|
|
myMusicWaveforms->setTarget(this);
|
|
myMusicWaveforms->setEditable(false);
|
|
|
|
// Current random number
|
|
lwidth = _font.getStringWidth("Current random number ");
|
|
xpos = 2; ypos += myLineHeight + 4;
|
|
new StaticTextWidget(boss, _font, xpos, ypos, lwidth,
|
|
myFontHeight, "Current random number ", TextAlign::Left);
|
|
xpos += lwidth;
|
|
|
|
myRandom = new DataGridWidget(boss, _nfont, xpos, ypos-2, 1, 1, 8, 32, Common::Base::Fmt::_16_8);
|
|
myRandom->setTarget(this);
|
|
myRandom->setEditable(false);
|
|
|
|
// Fast fetch and immediate mode LDA flags
|
|
xpos += myRandom->getWidth() + 30;
|
|
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 CartridgeDPCPlusWidget::saveOldState()
|
|
{
|
|
myOldState.tops.clear();
|
|
myOldState.bottoms.clear();
|
|
myOldState.counters.clear();
|
|
myOldState.fraccounters.clear();
|
|
myOldState.fracinc.clear();
|
|
myOldState.param.clear();
|
|
myOldState.mcounters.clear();
|
|
myOldState.mfreqs.clear();
|
|
myOldState.mwaves.clear();
|
|
myOldState.internalram.clear();
|
|
|
|
for(uInt32 i = 0; i < 8; ++i)
|
|
{
|
|
myOldState.tops.push_back(myCart.myTops[i]);
|
|
myOldState.bottoms.push_back(myCart.myBottoms[i]);
|
|
myOldState.counters.push_back(myCart.myCounters[i]);
|
|
myOldState.fraccounters.push_back(myCart.myFractionalCounters[i]);
|
|
myOldState.fracinc.push_back(myCart.myFractionalIncrements[i]);
|
|
myOldState.param.push_back(myCart.myParameter[i]);
|
|
}
|
|
for(uInt32 i = 0; i < 3; ++i)
|
|
{
|
|
myOldState.mcounters.push_back(myCart.myMusicCounters[i]);
|
|
myOldState.mfreqs.push_back(myCart.myMusicFrequencies[i]);
|
|
myOldState.mwaves.push_back(myCart.myMusicWaveforms[i]);
|
|
}
|
|
|
|
myOldState.random = myCart.myRandomNumber;
|
|
|
|
for(uInt32 i = 0; i < internalRamSize(); ++i)
|
|
myOldState.internalram.push_back(myCart.myDisplayImage[i]);
|
|
|
|
myOldState.bank = myCart.getBank();
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
void CartridgeDPCPlusWidget::loadConfig()
|
|
{
|
|
myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank);
|
|
|
|
// Get registers, using change tracking
|
|
IntArray alist;
|
|
IntArray vlist;
|
|
BoolArray changed;
|
|
|
|
alist.clear(); vlist.clear(); changed.clear();
|
|
for(int i = 0; i < 8; ++i)
|
|
{
|
|
alist.push_back(0); vlist.push_back(myCart.myTops[i]);
|
|
changed.push_back(myCart.myTops[i] != myOldState.tops[i]);
|
|
}
|
|
myTops->setList(alist, vlist, changed);
|
|
|
|
alist.clear(); vlist.clear(); changed.clear();
|
|
for(int i = 0; i < 8; ++i)
|
|
{
|
|
alist.push_back(0); vlist.push_back(myCart.myBottoms[i]);
|
|
changed.push_back(myCart.myBottoms[i] != myOldState.bottoms[i]);
|
|
}
|
|
myBottoms->setList(alist, vlist, changed);
|
|
|
|
alist.clear(); vlist.clear(); changed.clear();
|
|
for(int i = 0; i < 8; ++i)
|
|
{
|
|
alist.push_back(0); vlist.push_back(myCart.myCounters[i]);
|
|
changed.push_back(myCart.myCounters[i] != myOldState.counters[i]);
|
|
}
|
|
myCounters->setList(alist, vlist, changed);
|
|
|
|
alist.clear(); vlist.clear(); changed.clear();
|
|
for(int i = 0; i < 8; ++i)
|
|
{
|
|
alist.push_back(0); vlist.push_back(myCart.myFractionalCounters[i]);
|
|
changed.push_back(myCart.myFractionalCounters[i] != uInt32(myOldState.fraccounters[i]));
|
|
}
|
|
myFracCounters->setList(alist, vlist, changed);
|
|
|
|
alist.clear(); vlist.clear(); changed.clear();
|
|
for(int i = 0; i < 8; ++i)
|
|
{
|
|
alist.push_back(0); vlist.push_back(myCart.myFractionalIncrements[i]);
|
|
changed.push_back(myCart.myFractionalIncrements[i] != myOldState.fracinc[i]);
|
|
}
|
|
myFracIncrements->setList(alist, vlist, changed);
|
|
|
|
alist.clear(); vlist.clear(); changed.clear();
|
|
for(int i = 0; i < 8; ++i)
|
|
{
|
|
alist.push_back(0); vlist.push_back(myCart.myParameter[i]);
|
|
changed.push_back(myCart.myParameter[i] != myOldState.param[i]);
|
|
}
|
|
myParameter->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.myMusicWaveforms[i]);
|
|
changed.push_back(myCart.myMusicWaveforms[i] != myOldState.mwaves[i]);
|
|
}
|
|
myMusicWaveforms->setList(alist, vlist, changed);
|
|
|
|
myRandom->setList(0, myCart.myRandomNumber,
|
|
myCart.myRandomNumber != myOldState.random);
|
|
|
|
myFastFetch->setState(myCart.myFastFetch);
|
|
myIMLDA->setState(myCart.myLDAimmediate);
|
|
|
|
CartDebugWidget::loadConfig();
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
void CartridgeDPCPlusWidget::handleCommand(CommandSender* sender,
|
|
int cmd, int data, int id)
|
|
{
|
|
if(cmd == kBankChanged)
|
|
{
|
|
myCart.unlockBank();
|
|
myCart.bank(myBank->getSelected());
|
|
myCart.lockBank();
|
|
invalidate();
|
|
}
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
string CartridgeDPCPlusWidget::bankState()
|
|
{
|
|
ostringstream& buf = buffer();
|
|
|
|
static constexpr std::array<const char*, 6> spot = {
|
|
"$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB"
|
|
};
|
|
buf << "Bank = " << std::dec << myCart.getBank()
|
|
<< ", hotspot = " << spot[myCart.getBank()];
|
|
|
|
return buf.str();
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
uInt32 CartridgeDPCPlusWidget::internalRamSize()
|
|
{
|
|
return 5*1024;
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
uInt32 CartridgeDPCPlusWidget::internalRamRPort(int start)
|
|
{
|
|
return 0x0000 + start;
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
string CartridgeDPCPlusWidget::internalRamDescription()
|
|
{
|
|
ostringstream desc;
|
|
desc << "$0000 - $0FFF - 4K display data\n"
|
|
<< " indirectly accessible to 6507\n"
|
|
<< " via DPC+'s Data Fetcher registers\n"
|
|
<< "$1000 - $13FF - 1K frequency table,\n"
|
|
<< " C variables and C stack\n"
|
|
<< " not accessible to 6507";
|
|
|
|
return desc.str();
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
const ByteArray& CartridgeDPCPlusWidget::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& CartridgeDPCPlusWidget::internalRamCurrent(int start, int count)
|
|
{
|
|
myRamCurrent.clear();
|
|
for(int i = 0; i < count; i++)
|
|
myRamCurrent.push_back(myCart.myDisplayImage[start + i]);
|
|
return myRamCurrent;
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
void CartridgeDPCPlusWidget::internalRamSetValue(int addr, uInt8 value)
|
|
{
|
|
myCart.myDisplayImage[addr] = value;
|
|
}
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
uInt8 CartridgeDPCPlusWidget::internalRamGetValue(int addr)
|
|
{
|
|
return myCart.myDisplayImage[addr];
|
|
}
|