mirror of https://github.com/stella-emu/stella.git
further enhanced ARM cycle counts
This commit is contained in:
parent
22f9db40b9
commit
42f44b3bdb
|
@ -3543,14 +3543,23 @@
|
|||
compared to real hardware.</td>
|
||||
</tr><tr>
|
||||
<td><pre>-dev.thumb.incycles <1|0></pre></td>
|
||||
<td>When enabled, ARM emulation cycles are added to system cycles. This
|
||||
allows detecting timer overruns, but will also distort IRQ driven audio.</br>
|
||||
<td>When enabled, ARM emulation cycles are added to 6507 system cycles. This
|
||||
allows detecting timer overruns, but will also distort audio.</br>
|
||||
Note: The ARM emulation cycles are only a coarse approximation.
|
||||
</td>
|
||||
</tr><tr>
|
||||
<td><pre>-dev.thumb.cyclefactor <float></pre></td>
|
||||
<td>Adjust ARM emulation cycles by a factor (1.25 = default).
|
||||
</td>
|
||||
<td>Defines the ARM cycle count correction factor (default = 0.95).</td>
|
||||
</tr><tr>
|
||||
<td><pre>-dev.thumb.chiptype <0|1></pre></td>
|
||||
<td>Selects the emulated chip type (0 = LPC2103, 1 = LPC2104 family). This
|
||||
setting affects the CPU clock, the Flash memory access clock cycles and
|
||||
the number of Flash banks.</td>
|
||||
</tr><tr>
|
||||
<td><pre>-dev.thumb.mammode <0..3></pre></td>
|
||||
<td>Selects the Memory Accelerator Module (MAM) mode.</br>
|
||||
Note: Mode X (3) is for testing only. It reduces Flash memory access
|
||||
clock cycles to always 1.</td>
|
||||
</tr><tr>
|
||||
<td><pre>-<plr.|dev.>eepromaccess <1|0></pre></td>
|
||||
<td>When enabled, each read or write access to the AtariVox/SaveKey EEPROM is
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
#include <cmath>
|
||||
|
||||
#include "OSystem.hxx"
|
||||
#include "EditTextWidget.hxx"
|
||||
//#include "EditTextWidget.hxx"
|
||||
#include "PopUpWidget.hxx"
|
||||
#include "DataGridWidget.hxx"
|
||||
#include "CartARMWidget.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -35,125 +37,147 @@ void CartridgeARMWidget::addCycleWidgets(int xpos, int ypos)
|
|||
{
|
||||
const int INDENT = 20;
|
||||
const int VGAP = 4;
|
||||
VariantList items;
|
||||
|
||||
new StaticTextWidget(_boss, _font, xpos, ypos + 1, "ARM emulation cycles:");
|
||||
xpos += INDENT; ypos += myLineHeight + VGAP;
|
||||
myIncCycles = new CheckboxWidget(_boss, _font, xpos, ypos + 1, "Increase 6507 cycles", kIncCyclesChanged);
|
||||
myIncCycles = new CheckboxWidget(_boss, _font, xpos, ypos + 1, "Increase 6507 cycles",
|
||||
kIncCyclesChanged);
|
||||
myIncCycles->setToolTip("Increase 6507 cycles with approximated ARM cycles.");
|
||||
myIncCycles->setTarget(this);
|
||||
addFocusWidget(myIncCycles);
|
||||
|
||||
myCycleFactor = new SliderWidget(_boss, _font, myIncCycles->getRight() + _fontWidth * 2, ypos - 1,
|
||||
_fontWidth * 10, _lineHeight, "Factor ", _fontWidth * 7,
|
||||
_fontWidth * 10, _lineHeight, "Cycle factor", _fontWidth * 14,
|
||||
kFactorChanged, _fontWidth * 4, "%");
|
||||
myCycleFactor->setMinValue(90); myCycleFactor->setMaxValue(110);
|
||||
myCycleFactor->setMinValue(80); myCycleFactor->setMaxValue(100);
|
||||
myCycleFactor->setTickmarkIntervals(4);
|
||||
myCycleFactor->setToolTip("Multiply approximated ARM cycles by factor.");
|
||||
myCycleFactor->setToolTip("Correct approximated ARM cycles by factor.");
|
||||
myCycleFactor->setTarget(this);
|
||||
addFocusWidget(myCycleFactor);
|
||||
|
||||
ypos += myLineHeight + VGAP;
|
||||
StaticTextWidget* s = new StaticTextWidget(_boss, _font, xpos, ypos + 1, "Cycles ");
|
||||
ypos += (myLineHeight + VGAP) * 2;
|
||||
myCyclesLabel = new StaticTextWidget(_boss, _font, xpos, ypos + 1, "Cycles #");
|
||||
|
||||
myPrevThumbCycles = new EditTextWidget(_boss, _font, s->getRight(), ypos - 1,
|
||||
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
|
||||
myPrevThumbCycles = new DataGridWidget(_boss, _font, myCyclesLabel->getRight(), ypos - 1,
|
||||
1, 1, 6, 32, Common::Base::Fmt::_10_6);
|
||||
myPrevThumbCycles->setEditable(false);
|
||||
myPrevThumbCycles->setToolTip("Number of approximated CPU cycles of last but one ARM run.");
|
||||
myPrevThumbCycles->setToolTip("Approximated CPU cycles of last but one ARM run.\n");
|
||||
|
||||
myThumbCycles = new DataGridWidget(_boss, _font,
|
||||
myPrevThumbCycles->getRight() + _fontWidth / 2, ypos - 1,
|
||||
1, 1, 6, 32, Common::Base::Fmt::_10_6);
|
||||
|
||||
myThumbCycles = new EditTextWidget(_boss, _font, myPrevThumbCycles->getRight() + _fontWidth / 2, ypos - 1,
|
||||
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
|
||||
myThumbCycles->setEditable(false);
|
||||
myThumbCycles->setToolTip("Number of approximated CPU cycles of last ARM run.");
|
||||
myThumbCycles->setToolTip("Approximated CPU cycles of last ARM run.\n");
|
||||
|
||||
s = new StaticTextWidget(_boss, _font, myThumbCycles->getRight() + _fontWidth * 2, ypos + 1, "Fetches ");
|
||||
myPrevThumbFetches = new EditTextWidget(_boss, _font, s->getRight(), ypos - 1,
|
||||
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
|
||||
myPrevThumbFetches->setEditable(false);
|
||||
myPrevThumbFetches->setToolTip("Number of fetches/instructions of last but one ARM run.");
|
||||
StaticTextWidget* s = new StaticTextWidget(_boss, _font, myCycleFactor->getLeft(), ypos + 1,
|
||||
"Instructions #");
|
||||
|
||||
myThumbFetches = new EditTextWidget(_boss, _font, myPrevThumbFetches->getRight() + _fontWidth / 2, ypos - 1,
|
||||
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
|
||||
myThumbFetches->setEditable(false);
|
||||
myThumbFetches->setToolTip("Number of fetches/instructions of last ARM run.");
|
||||
myPrevThumbInstructions = new DataGridWidget(_boss, _font, s->getRight(), ypos - 1,
|
||||
1, 1, 6, 32, Common::Base::Fmt::_10_6);
|
||||
myPrevThumbInstructions->setEditable(false);
|
||||
myPrevThumbInstructions->setToolTip("Instructions of last but one ARM run.\n");
|
||||
|
||||
ypos += myLineHeight + VGAP;
|
||||
s = new StaticTextWidget(_boss, _font, xpos, ypos + 1, "Reads ");
|
||||
myThumbInstructions = new DataGridWidget(_boss, _font,
|
||||
myPrevThumbInstructions->getRight() + _fontWidth / 2, ypos - 1,
|
||||
1, 1, 6, 32, Common::Base::Fmt::_10_6);
|
||||
myThumbInstructions->setEditable(false);
|
||||
myThumbInstructions->setToolTip("Instructions of last ARM run.\n");
|
||||
|
||||
myPrevThumbReads = new EditTextWidget(_boss, _font, myPrevThumbCycles->getLeft(), ypos - 1,
|
||||
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
|
||||
myPrevThumbReads->setEditable(false);
|
||||
myPrevThumbReads->setToolTip("Number of reads of last but one ARM run.");
|
||||
// add later to allow aligning
|
||||
ypos -= myLineHeight + VGAP;
|
||||
int pwidth = myThumbCycles->getRight() - myPrevThumbCycles->getLeft()
|
||||
- PopUpWidget::dropDownWidth(_font);
|
||||
|
||||
myThumbReads = new EditTextWidget(_boss, _font, myThumbCycles->getLeft(), ypos - 1,
|
||||
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
|
||||
myThumbReads->setEditable(false);
|
||||
myThumbReads->setToolTip("Number of reads of last ARM run.");
|
||||
items.clear();
|
||||
VarList::push_back(items, "LPC2101/2/3", static_cast<uInt32>(Thumbulator::ChipType::LPC2103));
|
||||
VarList::push_back(items, "LPC2104/5/6", static_cast<uInt32>(Thumbulator::ChipType::LPC2104));
|
||||
myChipType = new PopUpWidget(_boss, _font, xpos, ypos, pwidth, myLineHeight, items,
|
||||
"Chip ", 0, kChipChanged);
|
||||
myChipType->setToolTip("Select emulated ARM chip.");
|
||||
myChipType->setTarget(this);
|
||||
|
||||
s = new StaticTextWidget(_boss, _font, myThumbReads->getRight() + _fontWidth * 2, ypos + 1, "Writes ");
|
||||
myLockMamMode = new CheckboxWidget(_boss, _font, myCycleFactor->getLeft(), ypos + 1, "MAM Mode",
|
||||
kMamLockChanged);
|
||||
myLockMamMode->setToolTip("Check to lock Memory Accelerator Module (MAM) mode.");
|
||||
myLockMamMode->setTarget(this);
|
||||
|
||||
myPrevThumbWrites = new EditTextWidget(_boss, _font, myPrevThumbFetches->getLeft(), ypos - 1,
|
||||
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
|
||||
myPrevThumbWrites->setEditable(false);
|
||||
myPrevThumbWrites->setToolTip("Number of writes of last but one ARM run.");
|
||||
pwidth = myThumbInstructions->getRight() - myPrevThumbInstructions->getLeft()
|
||||
- PopUpWidget::dropDownWidth(_font);
|
||||
items.clear();
|
||||
VarList::push_back(items, "Off (0)", static_cast<uInt32>(Thumbulator::MamModeType::mode0));
|
||||
VarList::push_back(items, "Partial (1)", static_cast<uInt32>(Thumbulator::MamModeType::mode1));
|
||||
VarList::push_back(items, "Full (2)", static_cast<uInt32>(Thumbulator::MamModeType::mode2));
|
||||
VarList::push_back(items, "1 Cycle (X)", static_cast<uInt32>(Thumbulator::MamModeType::modeX));
|
||||
myMamMode = new PopUpWidget(_boss, _font, myPrevThumbInstructions->getLeft(), ypos,
|
||||
pwidth, myLineHeight, items, "", 0, kMamModeChanged);
|
||||
myMamMode->setToolTip("Select emulated Memory Accelerator Module (MAM) mode.");
|
||||
myMamMode->setTarget(this);
|
||||
|
||||
myThumbWrites = new EditTextWidget(_boss, _font, myThumbFetches->getLeft(), ypos - 1,
|
||||
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
|
||||
myThumbWrites->setEditable(false);
|
||||
myThumbWrites->setToolTip("Number of writes of last ARM run.");
|
||||
// define the tab order
|
||||
addFocusWidget(myIncCycles);
|
||||
addFocusWidget(myCycleFactor);
|
||||
addFocusWidget(myChipType);
|
||||
addFocusWidget(myLockMamMode);
|
||||
addFocusWidget(myMamMode);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeARMWidget::saveOldState()
|
||||
{
|
||||
myOldState.armPrevStats.clear();
|
||||
myOldState.armStats.clear();
|
||||
myOldState.armPrevRun.clear();
|
||||
myOldState.armRun.clear();
|
||||
|
||||
myOldState.armPrevStats.push_back(myCart.prevStats().cycles);
|
||||
myOldState.armPrevStats.push_back(myCart.prevStats().fetches);
|
||||
myOldState.armPrevStats.push_back(myCart.prevStats().reads);
|
||||
myOldState.armPrevStats.push_back(myCart.prevStats().writes);
|
||||
myOldState.mamMode = static_cast<uInt32>(myCart.mamMode());
|
||||
|
||||
myOldState.armStats.push_back(myCart.stats().cycles);
|
||||
myOldState.armStats.push_back(myCart.stats().fetches);
|
||||
myOldState.armStats.push_back(myCart.stats().reads);
|
||||
myOldState.armStats.push_back(myCart.stats().writes);
|
||||
myOldState.armPrevRun.push_back(myCart.prevCycles());
|
||||
myOldState.armPrevRun.push_back(myCart.prevStats().instructions);
|
||||
|
||||
myOldState.armRun.push_back(myCart.cycles());
|
||||
myOldState.armRun.push_back(myCart.stats().instructions);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeARMWidget::loadConfig()
|
||||
{
|
||||
bool isChanged;
|
||||
bool devSettings = instance().settings().getBool("dev.settings");
|
||||
IntArray alist;
|
||||
IntArray vlist;
|
||||
BoolArray changed;
|
||||
|
||||
myChipType->setSelectedIndex(static_cast<uInt32>(instance().settings().getInt("dev.thumb.chiptype")));
|
||||
handleChipType();
|
||||
|
||||
isChanged = static_cast<uInt32>(myCart.mamMode()) != myOldState.mamMode;
|
||||
myMamMode->setSelectedIndex(static_cast<uInt32>(myCart.mamMode()), isChanged);
|
||||
myMamMode->setEnabled(devSettings && myLockMamMode->getState());
|
||||
myLockMamMode->setEnabled(devSettings);
|
||||
|
||||
// ARM cycles
|
||||
myIncCycles->setState(instance().settings().getBool("dev.thumb.inccycles"));
|
||||
myCycleFactor->setValue(std::round(instance().settings().getFloat("dev.thumb.cyclefactor") * 100.F));
|
||||
handleArmCycles();
|
||||
|
||||
bool isChanged;
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
alist.push_back(0); vlist.push_back(myCart.prevCycles());
|
||||
changed.push_back(myCart.prevCycles() != uInt32(myOldState.armPrevRun[0]));
|
||||
myPrevThumbCycles->setList(alist, vlist, changed);
|
||||
|
||||
isChanged = myCart.prevStats().cycles != myOldState.armPrevStats[0];
|
||||
myPrevThumbCycles->setText(Common::Base::toString(myCart.prevStats().cycles,
|
||||
Common::Base::Fmt::_10_6), isChanged);
|
||||
isChanged = myCart.prevStats().fetches != myOldState.armPrevStats[1];
|
||||
myPrevThumbFetches->setText(Common::Base::toString(myCart.prevStats().fetches,
|
||||
Common::Base::Fmt::_10_6), isChanged);
|
||||
isChanged = myCart.prevStats().reads != myOldState.armPrevStats[2];
|
||||
myPrevThumbReads->setText(Common::Base::toString(myCart.prevStats().reads,
|
||||
Common::Base::Fmt::_10_6), isChanged);
|
||||
isChanged = myCart.prevStats().writes != myOldState.armPrevStats[3];
|
||||
myPrevThumbWrites->setText(Common::Base::toString(myCart.prevStats().writes,
|
||||
Common::Base::Fmt::_10_6), isChanged);
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
alist.push_back(0); vlist.push_back(myCart.prevStats().instructions);
|
||||
changed.push_back(myCart.prevStats().instructions != uInt32(myOldState.armPrevRun[1]));
|
||||
myPrevThumbInstructions->setList(alist, vlist, changed);
|
||||
|
||||
isChanged = myCart.stats().cycles != myOldState.armStats[0];
|
||||
myThumbCycles->setText(Common::Base::toString(myCart.stats().cycles,
|
||||
Common::Base::Fmt::_10_6), isChanged);
|
||||
isChanged = myCart.stats().fetches != myOldState.armStats[1];
|
||||
myThumbFetches->setText(Common::Base::toString(myCart.stats().fetches,
|
||||
Common::Base::Fmt::_10_6), isChanged);
|
||||
isChanged = myCart.stats().reads != myOldState.armStats[2];
|
||||
myThumbReads->setText(Common::Base::toString(myCart.stats().reads,
|
||||
Common::Base::Fmt::_10_6), isChanged);
|
||||
isChanged = myCart.stats().writes != myOldState.armStats[3];
|
||||
myThumbWrites->setText(Common::Base::toString(myCart.stats().writes,
|
||||
Common::Base::Fmt::_10_6), isChanged);
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
alist.push_back(0); vlist.push_back(myCart.cycles());
|
||||
changed.push_back(myCart.cycles() != uInt32(myOldState.armRun[0]));
|
||||
myThumbCycles->setList(alist, vlist, changed);
|
||||
|
||||
|
||||
alist.clear(); vlist.clear(); changed.clear();
|
||||
alist.push_back(0); vlist.push_back(myCart.stats().instructions);
|
||||
changed.push_back(myCart.stats().instructions != uInt32(myOldState.armRun[1]));
|
||||
myThumbInstructions->setList(alist, vlist, changed);
|
||||
|
||||
CartDebugWidget::loadConfig();
|
||||
}
|
||||
|
@ -164,6 +188,18 @@ void CartridgeARMWidget::handleCommand(CommandSender* sender,
|
|||
{
|
||||
switch(cmd)
|
||||
{
|
||||
case kChipChanged:
|
||||
handleChipType();
|
||||
break;
|
||||
|
||||
case kMamLockChanged:
|
||||
handleMamLock();
|
||||
break;
|
||||
|
||||
case kMamModeChanged:
|
||||
handleMamMode();
|
||||
break;
|
||||
|
||||
case kIncCyclesChanged:
|
||||
case kFactorChanged:
|
||||
handleArmCycles();
|
||||
|
@ -174,6 +210,40 @@ void CartridgeARMWidget::handleCommand(CommandSender* sender,
|
|||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeARMWidget::handleChipType()
|
||||
{
|
||||
bool devSettings = instance().settings().getBool("dev.settings");
|
||||
|
||||
if(devSettings)
|
||||
{
|
||||
instance().settings().setValue("dev.thumb.chiptype", myChipType->getSelectedTag().toInt());
|
||||
}
|
||||
|
||||
myChipType->setEnabled(devSettings);
|
||||
|
||||
myCart.setChipType(static_cast<Thumbulator::ChipType>(myChipType->getSelectedTag().toInt()));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeARMWidget::handleMamLock()
|
||||
{
|
||||
bool checked = myLockMamMode->getState();
|
||||
|
||||
myMamMode->setEnabled(checked);
|
||||
myCart.lockMamMode(checked);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeARMWidget::handleMamMode()
|
||||
{
|
||||
// override MAM mode set by ROM
|
||||
Int32 mode = myMamMode->getSelectedTag().toInt();
|
||||
|
||||
instance().settings().setValue("dev.thumb.mammode", mode);
|
||||
myCart.setMamMode(static_cast<Thumbulator::MamModeType>(mode));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeARMWidget::handleArmCycles()
|
||||
{
|
||||
|
@ -188,8 +258,12 @@ void CartridgeARMWidget::handleArmCycles()
|
|||
}
|
||||
|
||||
myIncCycles->setEnabled(devSettings);
|
||||
enable &= devSettings;
|
||||
myCart.incCycles(enable);
|
||||
myCycleFactor->setEnabled(enable);
|
||||
myCycleFactor->setEnabled(devSettings);
|
||||
myCyclesLabel->setEnabled(devSettings);
|
||||
myThumbCycles->setEnabled(devSettings);
|
||||
myPrevThumbCycles->setEnabled(devSettings);
|
||||
|
||||
myCart.incCycles(devSettings && enable);
|
||||
myCart.cycleFactor(factor);
|
||||
myCart.enableCycleCount(devSettings);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
|
||||
class CheckboxWidget;
|
||||
class SliderWidget;
|
||||
class EditTextWidget;
|
||||
class PopUpWidget;
|
||||
class DataGridWidget;
|
||||
|
||||
/**
|
||||
Abstract base class for ARM cart widgets.
|
||||
|
@ -48,30 +49,37 @@ class CartridgeARMWidget : public CartDebugWidget
|
|||
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
|
||||
|
||||
private:
|
||||
void handleChipType();
|
||||
void handleMamLock();
|
||||
void handleMamMode();
|
||||
void handleArmCycles();
|
||||
|
||||
private:
|
||||
struct CartState {
|
||||
uIntArray armStats;
|
||||
uIntArray armPrevStats;
|
||||
uInt32 mamMode{0};
|
||||
uIntArray armRun;
|
||||
uIntArray armPrevRun;
|
||||
};
|
||||
|
||||
CartridgeARM& myCart;
|
||||
|
||||
CheckboxWidget* myIncCycles{nullptr};
|
||||
SliderWidget* myCycleFactor{nullptr};
|
||||
EditTextWidget* myPrevThumbCycles{nullptr};
|
||||
EditTextWidget* myPrevThumbFetches{nullptr};
|
||||
EditTextWidget* myPrevThumbReads{nullptr};
|
||||
EditTextWidget* myPrevThumbWrites{nullptr};
|
||||
EditTextWidget* myThumbCycles{nullptr};
|
||||
EditTextWidget* myThumbFetches{nullptr};
|
||||
EditTextWidget* myThumbReads{nullptr};
|
||||
EditTextWidget* myThumbWrites{nullptr};
|
||||
CheckboxWidget* myIncCycles{nullptr};
|
||||
SliderWidget* myCycleFactor{nullptr};
|
||||
PopUpWidget* myChipType{nullptr};
|
||||
CheckboxWidget* myLockMamMode{nullptr};
|
||||
PopUpWidget* myMamMode{nullptr};
|
||||
StaticTextWidget* myCyclesLabel{nullptr};
|
||||
DataGridWidget* myPrevThumbCycles{nullptr};
|
||||
DataGridWidget* myPrevThumbInstructions{nullptr};
|
||||
DataGridWidget* myThumbCycles{nullptr};
|
||||
DataGridWidget* myThumbInstructions{nullptr};
|
||||
|
||||
CartState myOldState;
|
||||
|
||||
enum {
|
||||
kChipChanged = 'chCh',
|
||||
kMamLockChanged = 'mlCh',
|
||||
kMamModeChanged = 'mmCh',
|
||||
kIncCyclesChanged = 'inCH',
|
||||
kFactorChanged = 'fcCH'
|
||||
};
|
||||
|
|
|
@ -23,17 +23,37 @@
|
|||
CartridgeARM::CartridgeARM(const string& md5, const Settings& settings)
|
||||
: Cartridge(settings, md5)
|
||||
{
|
||||
myIncCycles = settings.getBool("dev.settings")
|
||||
&& settings.getBool("dev.thumb.inccycles");
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeARM::setInitialState()
|
||||
{
|
||||
bool devSettings = mySettings.getBool("dev.settings");
|
||||
|
||||
if(devSettings)
|
||||
{
|
||||
myIncCycles = mySettings.getBool("dev.thumb.inccycles");
|
||||
myThumbEmulator->setChipType(static_cast<Thumbulator::ChipType>(mySettings.getInt("dev.thumb.chiptype")));
|
||||
myThumbEmulator->setMamMode(static_cast<Thumbulator::MamModeType>(mySettings.getInt("dev.thumb.mammode")));
|
||||
}
|
||||
else
|
||||
{
|
||||
myIncCycles = false;
|
||||
}
|
||||
enableCycleCount(devSettings);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void CartridgeARM::updateCycles(int cycles)
|
||||
{
|
||||
if(myIncCycles)
|
||||
mySystem->incrementCycles(cycles); // * ~1.11 is the limit for ZEVIOUZ title screen (~142,000 cycles)
|
||||
mySystem->incrementCycles(cycles);
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
myPrevStats = myStats;
|
||||
myStats = myThumbEmulator->stats();
|
||||
myPrevStats = myThumbEmulator->prevStats();
|
||||
myPrevCycles = myCycles;
|
||||
myCycles = myThumbEmulator->cycles();
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -51,43 +71,39 @@ void CartridgeARM::cycleFactor(double factor)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeARM::save(Serializer& out) const
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
try
|
||||
{
|
||||
out.putInt(myPrevStats.cycles);
|
||||
out.putInt(myPrevStats.fetches);
|
||||
out.putInt(myPrevStats.reads);
|
||||
out.putInt(myPrevStats.writes);
|
||||
out.putInt(myStats.cycles);
|
||||
out.putInt(myStats.fetches);
|
||||
out.putInt(myStats.reads);
|
||||
out.putInt(myStats.writes);
|
||||
out.putInt(myPrevCycles);
|
||||
out.putInt(myPrevStats.instructions);
|
||||
out.putInt(myCycles);
|
||||
out.putInt(myStats.instructions);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "ERROR: CartridgeARM::save" << endl;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool CartridgeARM::load(Serializer& in)
|
||||
{
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
try
|
||||
{
|
||||
myPrevStats.cycles = in.getInt();
|
||||
myPrevStats.fetches = in.getInt();
|
||||
myPrevStats.reads = in.getInt();
|
||||
myPrevStats.writes = in.getInt();
|
||||
myStats.cycles = in.getInt();
|
||||
myStats.fetches = in.getInt();
|
||||
myStats.reads = in.getInt();
|
||||
myStats.writes = in.getInt();
|
||||
myPrevCycles = in.getInt();
|
||||
myPrevStats.instructions = in.getInt();
|
||||
myCycles = in.getInt();
|
||||
myStats.instructions = in.getInt();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
cerr << "ERROR: CartridgeARM::load" << endl;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -51,15 +51,26 @@ class CartridgeARM : public Cartridge
|
|||
*/
|
||||
bool load(Serializer& in) override;
|
||||
|
||||
/**
|
||||
Sets the initial state of the MAM mode
|
||||
*/
|
||||
virtual void setInitialState();
|
||||
|
||||
void enableCycleCount(bool enable) const { myThumbEmulator->enableCycleCount(enable); }
|
||||
// Get number of memory accesses of last and last but one ARM runs.
|
||||
void updateCycles(int cycles);
|
||||
const Thumbulator::Stats& stats() const { return myStats; }
|
||||
const Thumbulator::Stats& prevStats() const { return myPrevStats; }
|
||||
const uInt32 cycles() const { return myCycles; }
|
||||
const uInt32 prevCycles() const { return myPrevCycles; }
|
||||
|
||||
void incCycles(bool enable);
|
||||
void cycleFactor(double factor);
|
||||
double cycleFactor() const { return myThumbEmulator->cycleFactor(); }
|
||||
|
||||
void setChipType(Thumbulator::ChipType armType) { myThumbEmulator->setChipType(armType); }
|
||||
void lockMamMode(bool lock) { myThumbEmulator->lockMamMode(lock); }
|
||||
void setMamMode(Thumbulator::MamModeType mamMode) { myThumbEmulator->setMamMode(mamMode); }
|
||||
Thumbulator::MamModeType mamMode() const { return myThumbEmulator->mamMode(); }
|
||||
|
||||
protected:
|
||||
// Pointer to the Thumb ARM emulator object
|
||||
|
@ -67,9 +78,12 @@ class CartridgeARM : public Cartridge
|
|||
|
||||
// ARM code increases 6507 cycles
|
||||
bool myIncCycles{false};
|
||||
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
Thumbulator::Stats myStats{0};
|
||||
Thumbulator::Stats myPrevStats{0};
|
||||
uInt32 myCycles{0};
|
||||
uInt32 myPrevCycles{0};
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
|
|
|
@ -112,6 +112,8 @@ void CartridgeBUS::setInitialState()
|
|||
mySTYZeroPageAddress = myJMPoperandAddress = 0;
|
||||
|
||||
myFastJumpActive = 0;
|
||||
|
||||
CartridgeARM::setInitialState();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -205,7 +205,7 @@ class CartridgeBUS : public CartridgeARM
|
|||
/**
|
||||
Sets the initial state of the DPC pointers and RAM
|
||||
*/
|
||||
void setInitialState();
|
||||
void setInitialState() override;
|
||||
|
||||
/**
|
||||
Updates any data fetchers in music mode based on the number of
|
||||
|
|
|
@ -145,6 +145,8 @@ void CartridgeCDF::setInitialState()
|
|||
|
||||
myBankOffset = myLDAimmediateOperandAddress = myJMPoperandAddress = 0;
|
||||
myFastJumpActive = myFastJumpStream = 0;
|
||||
|
||||
CartridgeARM::setInitialState();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -237,7 +237,7 @@ class CartridgeCDF : public CartridgeARM
|
|||
/**
|
||||
Sets the initial state of the DPC pointers and RAM
|
||||
*/
|
||||
void setInitialState();
|
||||
void setInitialState() override;
|
||||
|
||||
/**
|
||||
Updates any data fetchers in music mode based on the number of
|
||||
|
|
|
@ -118,6 +118,8 @@ void CartridgeDPCPlus::setInitialState()
|
|||
myFastFetch = myLDAimmediate = false;
|
||||
myAudioCycles = myARMCycles = 0;
|
||||
myFractionalClocks = 0.0;
|
||||
|
||||
CartridgeARM::setInitialState();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -199,7 +199,7 @@ class CartridgeDPCPlus : public CartridgeARM
|
|||
/**
|
||||
Sets the initial state of the DPC pointers and RAM
|
||||
*/
|
||||
void setInitialState();
|
||||
void setInitialState() override;
|
||||
|
||||
/**
|
||||
Clocks the random number generator to move it to its next state
|
||||
|
|
|
@ -246,8 +246,12 @@ Settings::Settings()
|
|||
setPermanent("dev.eepromaccess", "true");
|
||||
// Thumb ARM emulation options
|
||||
setPermanent("dev.thumb.trapfatal", "true");
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
setPermanent("dev.thumb.inccycles", "true");
|
||||
setPermanent("dev.thumb.cyclefactor", "1.05");
|
||||
setPermanent("dev.thumb.cyclefactor", "0.95");
|
||||
setPermanent("dev.thumb.chiptype", "0"); // = LPC2103
|
||||
setPermanent("dev.thumb.mammode", "2");
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -680,14 +684,19 @@ void Settings::usage() const
|
|||
<< " -dev.tiadriven <1|0> Drive unused TIA pins randomly on a\n"
|
||||
<< " read/peek\n"
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
<< " -dev.rwportbreak <1|0> Debugger breaks on reads from write ports\n"
|
||||
<< " -dev.wrportbreak <1|0> Debugger breaks on writes to read ports\n"
|
||||
<< " -dev.rwportbreak <1|0> Debugger breaks on reads from write ports\n"
|
||||
<< " -dev.wrportbreak <1|0> Debugger breaks on writes to read ports\n"
|
||||
#endif
|
||||
<< " -dev.thumb.trapfatal <1|0> Determines whether errors in ARM emulation\n"
|
||||
<< " -dev.thumb.trapfatal <1|0> Determines whether errors in ARM emulation\n"
|
||||
<< " throw an exception\n"
|
||||
<< " -dev.thumb.inccycles <1|0> Determines whether ARM emulation cycles\n"
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
<< " -dev.thumb.inccycles <1|0> Determines whether ARM emulation cycles\n"
|
||||
<< " increase system cycles\n"
|
||||
<< " -dev.eepromaccess <1|0> Enable messages for AtariVox/SaveKey access\n"
|
||||
<< " -dev.thumb.cyclefactor <float> Sets the ARM cycles correction multiplier\n"
|
||||
<< " -dev.thumb.chiptype <0|1> Selects the ARM chip type\n"
|
||||
<< " -dev.thumb.mammode <0-3> Selects the LPC's MAM mode\n"
|
||||
#endif
|
||||
<< " -dev.eepromaccess <1|0> Enable messages for AtariVox/SaveKey access\n"
|
||||
<< " messages\n"
|
||||
<< " -dev.tia.type <standard|custom| Selects a TIA type\n"
|
||||
<< " koolaidman|\n"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -32,7 +32,6 @@ class Cartridge;
|
|||
|
||||
#ifdef RETRON77
|
||||
#define UNSAFE_OPTIMIZATIONS
|
||||
#define NO_THUMB_STATS
|
||||
#endif
|
||||
|
||||
#define ROMADDMASK 0x7FFFF
|
||||
|
@ -46,8 +45,16 @@ class Cartridge;
|
|||
#define CPSR_C (1u<<29)
|
||||
#define CPSR_V (1u<<28)
|
||||
|
||||
#define TIMER_0 // enable timer 0 support
|
||||
//#define COUNT_OPS
|
||||
#ifdef DEBUGGER_SUPPORT
|
||||
#define THUMB_CYCLE_COUNT
|
||||
//#define COUNT_OPS
|
||||
//#define THUMB_STATS
|
||||
#endif
|
||||
|
||||
#ifdef THUMB_CYCLE_COUNT
|
||||
//#define EMULATE_PIPELINE // enable coarse ARM pipeline emulation
|
||||
#define TIMER_0 // enable timer 0 support (e.g. for measuring cycle count)
|
||||
#endif
|
||||
|
||||
class Thumbulator
|
||||
{
|
||||
|
@ -62,11 +69,24 @@ class Thumbulator
|
|||
CDFJplus, // cartridges of type CDFJ+
|
||||
DPCplus // cartridges of type DPC+
|
||||
};
|
||||
|
||||
enum class ChipType {
|
||||
LPC2103, // Harmony
|
||||
LPC2104, // Encore (includes LPC2105)
|
||||
LPC2132, // future use
|
||||
numTypes
|
||||
};
|
||||
enum class MamModeType {
|
||||
mode0, mode1, mode2, modeX
|
||||
};
|
||||
struct ChipPropsType {
|
||||
double MHz;
|
||||
uInt32 flashCycles;
|
||||
uInt32 flashBanks;
|
||||
};
|
||||
struct Stats {
|
||||
#ifndef NO_THUMB_STATS
|
||||
uInt32 fetches{0}, reads{0}, writes{0};
|
||||
uInt32 cycles{0};
|
||||
uInt32 instructions{0};
|
||||
#ifdef THUMB_STATS
|
||||
uInt32 reads{0}, writes{0};
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -86,10 +106,23 @@ class Thumbulator
|
|||
*/
|
||||
string doRun(uInt32& cycles);
|
||||
string run(uInt32& cycles);
|
||||
void enableCycleCount(bool enable) { _countCycles = enable; }
|
||||
const Stats& stats() const { return _stats; }
|
||||
const Stats& prevStats() const { return _prevStats; }
|
||||
const uInt32 cycles() const { return _totalCycles; }
|
||||
void setChipType(ChipType type);
|
||||
void setMamMode(MamModeType mode) { mamcr = mode; }
|
||||
void lockMamMode(bool lock) { _lockMamcr = lock; }
|
||||
MamModeType mamMode() const { return static_cast<MamModeType>(mamcr); }
|
||||
|
||||
#ifndef UNSAFE_OPTIMIZATIONS
|
||||
#ifdef THUMB_CYCLE_COUNT
|
||||
void cycleFactor(double factor) { _armCyclesFactor = factor; }
|
||||
double cycleFactor() const { return _armCyclesFactor; }
|
||||
#else
|
||||
void cycleFactor(double) { }
|
||||
double cycleFactor() const { return 1.0; }
|
||||
#endif
|
||||
|
||||
#ifndef UNSAFE_OPTIMIZATIONS
|
||||
/**
|
||||
Normally when a fatal error is encountered, the ARM emulation
|
||||
immediately throws an exception and exits. This method allows execution
|
||||
|
@ -102,15 +135,8 @@ class Thumbulator
|
|||
|
||||
@param enable Enable (the default) or disable exceptions on fatal errors
|
||||
*/
|
||||
static void trapFatalErrors(bool enable) { trapOnFatal = enable; }
|
||||
#endif
|
||||
#ifndef NO_THUMB_STATS
|
||||
static void cycleFactor(double factor) { arm_cycle_factor = factor; }
|
||||
double cycleFactor() const { return arm_cycle_factor; }
|
||||
#else
|
||||
static void cycleFactor(double) { }
|
||||
double cycleFactor() const { return 1.0; }
|
||||
#endif
|
||||
void trapFatalErrors(bool enable) { trapOnFatal = enable; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
Inform the Thumbulator class about the console currently in use,
|
||||
|
@ -171,16 +197,24 @@ class Thumbulator
|
|||
uxth,
|
||||
numOps
|
||||
};
|
||||
#ifdef THUMB_CYCLE_COUNT
|
||||
enum class CycleType {
|
||||
S, N, I // Sequential, Non-sequential, Internal
|
||||
};
|
||||
enum class AccessType {
|
||||
prefetch, branch, data
|
||||
};
|
||||
#endif
|
||||
|
||||
private:
|
||||
uInt32 read_register(uInt32 reg);
|
||||
void write_register(uInt32 reg, uInt32 data);
|
||||
void write_register(uInt32 reg, uInt32 data, bool isFlowBreak = true);
|
||||
uInt32 fetch16(uInt32 addr);
|
||||
uInt32 read16(uInt32 addr);
|
||||
uInt32 read32(uInt32 addr);
|
||||
#ifndef UNSAFE_OPTIMIZATIONS
|
||||
#ifndef UNSAFE_OPTIMIZATIONS
|
||||
bool isProtected(uInt32 addr);
|
||||
#endif
|
||||
#endif
|
||||
void write16(uInt32 addr, uInt32 data);
|
||||
void write32(uInt32 addr, uInt32 data);
|
||||
void updateTimer(uInt32 cycles);
|
||||
|
@ -194,7 +228,7 @@ class Thumbulator
|
|||
void do_cflag_bit(uInt32 x);
|
||||
void do_vflag_bit(uInt32 x);
|
||||
|
||||
#ifndef UNSAFE_OPTIMIZATIONS
|
||||
#ifndef UNSAFE_OPTIMIZATIONS
|
||||
// Throw a runtime_error exception containing an error referencing the
|
||||
// given message and variables
|
||||
// Note that the return value is never used in these methods
|
||||
|
@ -203,10 +237,18 @@ class Thumbulator
|
|||
|
||||
void dump_counters();
|
||||
void dump_regs();
|
||||
#endif
|
||||
#endif
|
||||
int execute();
|
||||
int reset();
|
||||
|
||||
#ifdef THUMB_CYCLE_COUNT
|
||||
bool isMamBuffered(uInt32 addr, AccessType = AccessType::data);
|
||||
void incCycles(AccessType accessType, uInt32 cycles);
|
||||
void incSCycles(uInt32 addr, AccessType = AccessType::data);
|
||||
void incNCycles(uInt32 addr, AccessType = AccessType::data);
|
||||
void incICycles(uInt32 m = 1);
|
||||
#endif
|
||||
|
||||
private:
|
||||
const uInt16* rom{nullptr};
|
||||
uInt32 romSize{0};
|
||||
|
@ -216,16 +258,17 @@ class Thumbulator
|
|||
const unique_ptr<Op[]> decodedRom; // NOLINT
|
||||
uInt16* ram{nullptr};
|
||||
std::array<uInt32, 16> reg_norm; // normal execution mode, do not have a thread mode
|
||||
uInt32 cpsr{0}, mamcr{0};
|
||||
uInt32 cpsr{0};
|
||||
MamModeType mamcr{MamModeType::mode0};
|
||||
bool handler_mode{false};
|
||||
uInt32 systick_ctrl{0}, systick_reload{0}, systick_count{0}, systick_calibrate{0};
|
||||
#ifndef UNSAFE_OPTIMIZATIONS
|
||||
uInt32 instructions{0};
|
||||
#endif
|
||||
#ifndef NO_THUMB_STATS
|
||||
Stats _stats;
|
||||
Stats _prevStats;
|
||||
#endif
|
||||
ChipType _chipType{ChipType::LPC2103};
|
||||
ConsoleTiming _consoleTiming{ConsoleTiming::ntsc};
|
||||
double _MHz{70.0};
|
||||
uInt32 _flashCycles{4};
|
||||
uInt32 _flashBanks{1};
|
||||
Stats _stats{0};
|
||||
uInt32 _totalCycles{0};
|
||||
|
||||
// For emulation of LPC2103's timer 1, used for NTSC/PAL/SECAM detection.
|
||||
// Register names from documentation:
|
||||
|
@ -240,17 +283,34 @@ class Thumbulator
|
|||
uInt32 tim1Cycles{0};
|
||||
double timing_factor{0.0};
|
||||
|
||||
#ifndef UNSAFE_OPTIMIZATIONS
|
||||
#ifndef UNSAFE_OPTIMIZATIONS
|
||||
ostringstream statusMsg;
|
||||
bool trapOnFatal{true};
|
||||
#endif
|
||||
const std::array<ChipPropsType, uInt32(ChipType::numTypes)> ChipProps =
|
||||
{{
|
||||
{ 70.0, 4, 1 }, // LPC2101_02_03
|
||||
{ 60.0, 3, 2 }, // LPC2104_05_06
|
||||
{ 60.0, 3, 1 }, // LPC2132..
|
||||
}};
|
||||
|
||||
static bool trapOnFatal;
|
||||
#endif
|
||||
#ifndef NO_THUMB_STATS
|
||||
static double arm_cycle_factor;
|
||||
#endif
|
||||
#ifdef COUNT_OPS
|
||||
bool _countCycles{false};
|
||||
bool _lockMamcr{false};
|
||||
|
||||
#ifdef THUMB_CYCLE_COUNT
|
||||
double _armCyclesFactor{0.90};
|
||||
CycleType _fetchCycleType{CycleType::S};
|
||||
#ifdef EMULATE_PIPELINE
|
||||
uInt32 _fetchPipeline{0}; // reserve fetch cycles resulting from pipelining (execution stage)
|
||||
uInt32 _memory0Pipeline{0}, _memory1Pipeline{0};
|
||||
#endif
|
||||
uInt32 _prefetchBufferAddr[2]{0};
|
||||
uInt32 _branchBufferAddr[2]{0};
|
||||
uInt32 _dataBufferAddr{0};
|
||||
#endif
|
||||
#ifdef COUNT_OPS
|
||||
uInt32 opCount[size_t(Op::numOps)]{0};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ConfigureFor configuration;
|
||||
|
||||
|
|
|
@ -740,8 +740,7 @@ void VideoAudioDialog::saveConfig()
|
|||
/////////////////////////////////////////////////////////////////////////////
|
||||
// TV Effects tab
|
||||
// TV Mode
|
||||
settings.setValue("tv.filter",
|
||||
myTVMode->getSelectedTag().toString());
|
||||
settings.setValue("tv.filter", myTVMode->getSelectedTag().toString());
|
||||
// TV Custom adjustables
|
||||
NTSCFilter::Adjustable ntscAdj;
|
||||
ntscAdj.sharpness = myTVSharp->getValue();
|
||||
|
|
Loading…
Reference in New Issue