further enhanced ARM cycle counts

This commit is contained in:
Thomas Jentzsch 2021-06-24 16:21:00 +02:00
parent 22f9db40b9
commit 42f44b3bdb
15 changed files with 772 additions and 391 deletions

View File

@ -3543,14 +3543,23 @@
compared to real hardware.</td> compared to real hardware.</td>
</tr><tr> </tr><tr>
<td><pre>-dev.thumb.incycles &lt;1|0&gt;</pre></td> <td><pre>-dev.thumb.incycles &lt;1|0&gt;</pre></td>
<td>When enabled, ARM emulation cycles are added to system cycles. This <td>When enabled, ARM emulation cycles are added to 6507 system cycles. This
allows detecting timer overruns, but will also distort IRQ driven audio.</br> allows detecting timer overruns, but will also distort audio.</br>
Note: The ARM emulation cycles are only a coarse approximation. Note: The ARM emulation cycles are only a coarse approximation.
</td> </td>
</tr><tr> </tr><tr>
<td><pre>-dev.thumb.cyclefactor &lt;float&gt;</pre></td> <td><pre>-dev.thumb.cyclefactor &lt;float&gt;</pre></td>
<td>Adjust ARM emulation cycles by a factor (1.25 = default). <td>Defines the ARM cycle count correction factor (default = 0.95).</td>
</td> </tr><tr>
<td><pre>-dev.thumb.chiptype &lt;0|1&gt;</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 &lt;0..3&gt;</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> </tr><tr>
<td><pre>-&lt;plr.|dev.&gt;eepromaccess &lt;1|0&gt;</pre></td> <td><pre>-&lt;plr.|dev.&gt;eepromaccess &lt;1|0&gt;</pre></td>
<td>When enabled, each read or write access to the AtariVox/SaveKey EEPROM is <td>When enabled, each read or write access to the AtariVox/SaveKey EEPROM is

View File

@ -18,7 +18,9 @@
#include <cmath> #include <cmath>
#include "OSystem.hxx" #include "OSystem.hxx"
#include "EditTextWidget.hxx" //#include "EditTextWidget.hxx"
#include "PopUpWidget.hxx"
#include "DataGridWidget.hxx"
#include "CartARMWidget.hxx" #include "CartARMWidget.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -35,125 +37,147 @@ void CartridgeARMWidget::addCycleWidgets(int xpos, int ypos)
{ {
const int INDENT = 20; const int INDENT = 20;
const int VGAP = 4; const int VGAP = 4;
VariantList items;
new StaticTextWidget(_boss, _font, xpos, ypos + 1, "ARM emulation cycles:"); new StaticTextWidget(_boss, _font, xpos, ypos + 1, "ARM emulation cycles:");
xpos += INDENT; ypos += myLineHeight + VGAP; 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->setToolTip("Increase 6507 cycles with approximated ARM cycles.");
myIncCycles->setTarget(this); myIncCycles->setTarget(this);
addFocusWidget(myIncCycles);
myCycleFactor = new SliderWidget(_boss, _font, myIncCycles->getRight() + _fontWidth * 2, ypos - 1, 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, "%"); kFactorChanged, _fontWidth * 4, "%");
myCycleFactor->setMinValue(90); myCycleFactor->setMaxValue(110); myCycleFactor->setMinValue(80); myCycleFactor->setMaxValue(100);
myCycleFactor->setTickmarkIntervals(4); myCycleFactor->setTickmarkIntervals(4);
myCycleFactor->setToolTip("Multiply approximated ARM cycles by factor."); myCycleFactor->setToolTip("Correct approximated ARM cycles by factor.");
myCycleFactor->setTarget(this); myCycleFactor->setTarget(this);
addFocusWidget(myCycleFactor);
ypos += myLineHeight + VGAP; ypos += (myLineHeight + VGAP) * 2;
StaticTextWidget* s = new StaticTextWidget(_boss, _font, xpos, ypos + 1, "Cycles "); myCyclesLabel = new StaticTextWidget(_boss, _font, xpos, ypos + 1, "Cycles #");
myPrevThumbCycles = new EditTextWidget(_boss, _font, s->getRight(), ypos - 1, myPrevThumbCycles = new DataGridWidget(_boss, _font, myCyclesLabel->getRight(), ypos - 1,
EditTextWidget::calcWidth(_font, 6), myLineHeight, ""); 1, 1, 6, 32, Common::Base::Fmt::_10_6);
myPrevThumbCycles->setEditable(false); 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->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 "); StaticTextWidget* s = new StaticTextWidget(_boss, _font, myCycleFactor->getLeft(), ypos + 1,
myPrevThumbFetches = new EditTextWidget(_boss, _font, s->getRight(), ypos - 1, "Instructions #");
EditTextWidget::calcWidth(_font, 6), myLineHeight, "");
myPrevThumbFetches->setEditable(false);
myPrevThumbFetches->setToolTip("Number of fetches/instructions of last but one ARM run.");
myThumbFetches = new EditTextWidget(_boss, _font, myPrevThumbFetches->getRight() + _fontWidth / 2, ypos - 1, myPrevThumbInstructions = new DataGridWidget(_boss, _font, s->getRight(), ypos - 1,
EditTextWidget::calcWidth(_font, 6), myLineHeight, ""); 1, 1, 6, 32, Common::Base::Fmt::_10_6);
myThumbFetches->setEditable(false); myPrevThumbInstructions->setEditable(false);
myThumbFetches->setToolTip("Number of fetches/instructions of last ARM run."); myPrevThumbInstructions->setToolTip("Instructions of last but one ARM run.\n");
ypos += myLineHeight + VGAP; myThumbInstructions = new DataGridWidget(_boss, _font,
s = new StaticTextWidget(_boss, _font, xpos, ypos + 1, "Reads "); 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, // add later to allow aligning
EditTextWidget::calcWidth(_font, 6), myLineHeight, ""); ypos -= myLineHeight + VGAP;
myPrevThumbReads->setEditable(false); int pwidth = myThumbCycles->getRight() - myPrevThumbCycles->getLeft()
myPrevThumbReads->setToolTip("Number of reads of last but one ARM run."); - PopUpWidget::dropDownWidth(_font);
myThumbReads = new EditTextWidget(_boss, _font, myThumbCycles->getLeft(), ypos - 1, items.clear();
EditTextWidget::calcWidth(_font, 6), myLineHeight, ""); VarList::push_back(items, "LPC2101/2/3", static_cast<uInt32>(Thumbulator::ChipType::LPC2103));
myThumbReads->setEditable(false); VarList::push_back(items, "LPC2104/5/6", static_cast<uInt32>(Thumbulator::ChipType::LPC2104));
myThumbReads->setToolTip("Number of reads of last ARM run."); 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, pwidth = myThumbInstructions->getRight() - myPrevThumbInstructions->getLeft()
EditTextWidget::calcWidth(_font, 6), myLineHeight, ""); - PopUpWidget::dropDownWidth(_font);
myPrevThumbWrites->setEditable(false); items.clear();
myPrevThumbWrites->setToolTip("Number of writes of last but one ARM run."); 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, // define the tab order
EditTextWidget::calcWidth(_font, 6), myLineHeight, ""); addFocusWidget(myIncCycles);
myThumbWrites->setEditable(false); addFocusWidget(myCycleFactor);
myThumbWrites->setToolTip("Number of writes of last ARM run."); addFocusWidget(myChipType);
addFocusWidget(myLockMamMode);
addFocusWidget(myMamMode);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARMWidget::saveOldState() void CartridgeARMWidget::saveOldState()
{ {
myOldState.armPrevStats.clear(); myOldState.armPrevRun.clear();
myOldState.armStats.clear(); myOldState.armRun.clear();
myOldState.armPrevStats.push_back(myCart.prevStats().cycles); myOldState.mamMode = static_cast<uInt32>(myCart.mamMode());
myOldState.armPrevStats.push_back(myCart.prevStats().fetches);
myOldState.armPrevStats.push_back(myCart.prevStats().reads);
myOldState.armPrevStats.push_back(myCart.prevStats().writes);
myOldState.armStats.push_back(myCart.stats().cycles); myOldState.armPrevRun.push_back(myCart.prevCycles());
myOldState.armStats.push_back(myCart.stats().fetches); myOldState.armPrevRun.push_back(myCart.prevStats().instructions);
myOldState.armStats.push_back(myCart.stats().reads);
myOldState.armStats.push_back(myCart.stats().writes); myOldState.armRun.push_back(myCart.cycles());
myOldState.armRun.push_back(myCart.stats().instructions);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CartridgeARMWidget::loadConfig() 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 // ARM cycles
myIncCycles->setState(instance().settings().getBool("dev.thumb.inccycles")); myIncCycles->setState(instance().settings().getBool("dev.thumb.inccycles"));
myCycleFactor->setValue(std::round(instance().settings().getFloat("dev.thumb.cyclefactor") * 100.F)); myCycleFactor->setValue(std::round(instance().settings().getFloat("dev.thumb.cyclefactor") * 100.F));
handleArmCycles(); 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]; alist.clear(); vlist.clear(); changed.clear();
myPrevThumbCycles->setText(Common::Base::toString(myCart.prevStats().cycles, alist.push_back(0); vlist.push_back(myCart.prevStats().instructions);
Common::Base::Fmt::_10_6), isChanged); changed.push_back(myCart.prevStats().instructions != uInt32(myOldState.armPrevRun[1]));
isChanged = myCart.prevStats().fetches != myOldState.armPrevStats[1]; myPrevThumbInstructions->setList(alist, vlist, changed);
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);
isChanged = myCart.stats().cycles != myOldState.armStats[0]; alist.clear(); vlist.clear(); changed.clear();
myThumbCycles->setText(Common::Base::toString(myCart.stats().cycles, alist.push_back(0); vlist.push_back(myCart.cycles());
Common::Base::Fmt::_10_6), isChanged); changed.push_back(myCart.cycles() != uInt32(myOldState.armRun[0]));
isChanged = myCart.stats().fetches != myOldState.armStats[1]; myThumbCycles->setList(alist, vlist, changed);
myThumbFetches->setText(Common::Base::toString(myCart.stats().fetches,
Common::Base::Fmt::_10_6), isChanged);
isChanged = myCart.stats().reads != myOldState.armStats[2]; alist.clear(); vlist.clear(); changed.clear();
myThumbReads->setText(Common::Base::toString(myCart.stats().reads, alist.push_back(0); vlist.push_back(myCart.stats().instructions);
Common::Base::Fmt::_10_6), isChanged); changed.push_back(myCart.stats().instructions != uInt32(myOldState.armRun[1]));
isChanged = myCart.stats().writes != myOldState.armStats[3]; myThumbInstructions->setList(alist, vlist, changed);
myThumbWrites->setText(Common::Base::toString(myCart.stats().writes,
Common::Base::Fmt::_10_6), isChanged);
CartDebugWidget::loadConfig(); CartDebugWidget::loadConfig();
} }
@ -164,6 +188,18 @@ void CartridgeARMWidget::handleCommand(CommandSender* sender,
{ {
switch(cmd) switch(cmd)
{ {
case kChipChanged:
handleChipType();
break;
case kMamLockChanged:
handleMamLock();
break;
case kMamModeChanged:
handleMamMode();
break;
case kIncCyclesChanged: case kIncCyclesChanged:
case kFactorChanged: case kFactorChanged:
handleArmCycles(); 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() void CartridgeARMWidget::handleArmCycles()
{ {
@ -188,8 +258,12 @@ void CartridgeARMWidget::handleArmCycles()
} }
myIncCycles->setEnabled(devSettings); myIncCycles->setEnabled(devSettings);
enable &= devSettings; myCycleFactor->setEnabled(devSettings);
myCart.incCycles(enable); myCyclesLabel->setEnabled(devSettings);
myCycleFactor->setEnabled(enable); myThumbCycles->setEnabled(devSettings);
myPrevThumbCycles->setEnabled(devSettings);
myCart.incCycles(devSettings && enable);
myCart.cycleFactor(factor); myCart.cycleFactor(factor);
myCart.enableCycleCount(devSettings);
} }

View File

@ -23,7 +23,8 @@
class CheckboxWidget; class CheckboxWidget;
class SliderWidget; class SliderWidget;
class EditTextWidget; class PopUpWidget;
class DataGridWidget;
/** /**
Abstract base class for ARM cart widgets. 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; void handleCommand(CommandSender* sender, int cmd, int data, int id) override;
private: private:
void handleChipType();
void handleMamLock();
void handleMamMode();
void handleArmCycles(); void handleArmCycles();
private: private:
struct CartState { struct CartState {
uIntArray armStats; uInt32 mamMode{0};
uIntArray armPrevStats; uIntArray armRun;
uIntArray armPrevRun;
}; };
CartridgeARM& myCart; CartridgeARM& myCart;
CheckboxWidget* myIncCycles{nullptr}; CheckboxWidget* myIncCycles{nullptr};
SliderWidget* myCycleFactor{nullptr}; SliderWidget* myCycleFactor{nullptr};
EditTextWidget* myPrevThumbCycles{nullptr}; PopUpWidget* myChipType{nullptr};
EditTextWidget* myPrevThumbFetches{nullptr}; CheckboxWidget* myLockMamMode{nullptr};
EditTextWidget* myPrevThumbReads{nullptr}; PopUpWidget* myMamMode{nullptr};
EditTextWidget* myPrevThumbWrites{nullptr}; StaticTextWidget* myCyclesLabel{nullptr};
EditTextWidget* myThumbCycles{nullptr}; DataGridWidget* myPrevThumbCycles{nullptr};
EditTextWidget* myThumbFetches{nullptr}; DataGridWidget* myPrevThumbInstructions{nullptr};
EditTextWidget* myThumbReads{nullptr}; DataGridWidget* myThumbCycles{nullptr};
EditTextWidget* myThumbWrites{nullptr}; DataGridWidget* myThumbInstructions{nullptr};
CartState myOldState; CartState myOldState;
enum { enum {
kChipChanged = 'chCh',
kMamLockChanged = 'mlCh',
kMamModeChanged = 'mmCh',
kIncCyclesChanged = 'inCH', kIncCyclesChanged = 'inCH',
kFactorChanged = 'fcCH' kFactorChanged = 'fcCH'
}; };

View File

@ -23,17 +23,37 @@
CartridgeARM::CartridgeARM(const string& md5, const Settings& settings) CartridgeARM::CartridgeARM(const string& md5, const Settings& settings)
: Cartridge(settings, md5) : 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) void CartridgeARM::updateCycles(int cycles)
{ {
if(myIncCycles) 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(); 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 bool CartridgeARM::save(Serializer& out) const
{ {
#ifdef DEBUGGER_SUPPORT
try try
{ {
out.putInt(myPrevStats.cycles); out.putInt(myPrevCycles);
out.putInt(myPrevStats.fetches); out.putInt(myPrevStats.instructions);
out.putInt(myPrevStats.reads); out.putInt(myCycles);
out.putInt(myPrevStats.writes); out.putInt(myStats.instructions);
out.putInt(myStats.cycles);
out.putInt(myStats.fetches);
out.putInt(myStats.reads);
out.putInt(myStats.writes);
} }
catch(...) catch(...)
{ {
cerr << "ERROR: CartridgeARM::save" << endl; cerr << "ERROR: CartridgeARM::save" << endl;
return false; return false;
} }
#endif
return true; return true;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool CartridgeARM::load(Serializer& in) bool CartridgeARM::load(Serializer& in)
{ {
#ifdef DEBUGGER_SUPPORT
try try
{ {
myPrevStats.cycles = in.getInt(); myPrevCycles = in.getInt();
myPrevStats.fetches = in.getInt(); myPrevStats.instructions = in.getInt();
myPrevStats.reads = in.getInt(); myCycles = in.getInt();
myPrevStats.writes = in.getInt(); myStats.instructions = in.getInt();
myStats.cycles = in.getInt();
myStats.fetches = in.getInt();
myStats.reads = in.getInt();
myStats.writes = in.getInt();
} }
catch(...) catch(...)
{ {
cerr << "ERROR: CartridgeARM::load" << endl; cerr << "ERROR: CartridgeARM::load" << endl;
return false; return false;
} }
#endif
return true; return true;
} }

View File

@ -51,15 +51,26 @@ class CartridgeARM : public Cartridge
*/ */
bool load(Serializer& in) override; 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. // Get number of memory accesses of last and last but one ARM runs.
void updateCycles(int cycles); void updateCycles(int cycles);
const Thumbulator::Stats& stats() const { return myStats; } const Thumbulator::Stats& stats() const { return myStats; }
const Thumbulator::Stats& prevStats() const { return myPrevStats; } const Thumbulator::Stats& prevStats() const { return myPrevStats; }
const uInt32 cycles() const { return myCycles; }
const uInt32 prevCycles() const { return myPrevCycles; }
void incCycles(bool enable); void incCycles(bool enable);
void cycleFactor(double factor); void cycleFactor(double factor);
double cycleFactor() const { return myThumbEmulator->cycleFactor(); } 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: protected:
// Pointer to the Thumb ARM emulator object // Pointer to the Thumb ARM emulator object
@ -67,9 +78,12 @@ class CartridgeARM : public Cartridge
// ARM code increases 6507 cycles // ARM code increases 6507 cycles
bool myIncCycles{false}; bool myIncCycles{false};
#ifdef DEBUGGER_SUPPORT
Thumbulator::Stats myStats{0}; Thumbulator::Stats myStats{0};
Thumbulator::Stats myPrevStats{0}; Thumbulator::Stats myPrevStats{0};
uInt32 myCycles{0};
uInt32 myPrevCycles{0};
#endif
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported

View File

@ -112,6 +112,8 @@ void CartridgeBUS::setInitialState()
mySTYZeroPageAddress = myJMPoperandAddress = 0; mySTYZeroPageAddress = myJMPoperandAddress = 0;
myFastJumpActive = 0; myFastJumpActive = 0;
CartridgeARM::setInitialState();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -205,7 +205,7 @@ class CartridgeBUS : public CartridgeARM
/** /**
Sets the initial state of the DPC pointers and RAM 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 Updates any data fetchers in music mode based on the number of

View File

@ -145,6 +145,8 @@ void CartridgeCDF::setInitialState()
myBankOffset = myLDAimmediateOperandAddress = myJMPoperandAddress = 0; myBankOffset = myLDAimmediateOperandAddress = myJMPoperandAddress = 0;
myFastJumpActive = myFastJumpStream = 0; myFastJumpActive = myFastJumpStream = 0;
CartridgeARM::setInitialState();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -237,7 +237,7 @@ class CartridgeCDF : public CartridgeARM
/** /**
Sets the initial state of the DPC pointers and RAM 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 Updates any data fetchers in music mode based on the number of

View File

@ -118,6 +118,8 @@ void CartridgeDPCPlus::setInitialState()
myFastFetch = myLDAimmediate = false; myFastFetch = myLDAimmediate = false;
myAudioCycles = myARMCycles = 0; myAudioCycles = myARMCycles = 0;
myFractionalClocks = 0.0; myFractionalClocks = 0.0;
CartridgeARM::setInitialState();
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -199,7 +199,7 @@ class CartridgeDPCPlus : public CartridgeARM
/** /**
Sets the initial state of the DPC pointers and RAM 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 Clocks the random number generator to move it to its next state

View File

@ -246,8 +246,12 @@ Settings::Settings()
setPermanent("dev.eepromaccess", "true"); setPermanent("dev.eepromaccess", "true");
// Thumb ARM emulation options // Thumb ARM emulation options
setPermanent("dev.thumb.trapfatal", "true"); setPermanent("dev.thumb.trapfatal", "true");
#ifdef DEBUGGER_SUPPORT
setPermanent("dev.thumb.inccycles", "true"); 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" << " -dev.tiadriven <1|0> Drive unused TIA pins randomly on a\n"
<< " read/peek\n" << " read/peek\n"
#ifdef DEBUGGER_SUPPORT #ifdef DEBUGGER_SUPPORT
<< " -dev.rwportbreak <1|0> Debugger breaks on reads from write 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" << " -dev.wrportbreak <1|0> Debugger breaks on writes to read ports\n"
#endif #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" << " 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" << " 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" << " messages\n"
<< " -dev.tia.type <standard|custom| Selects a TIA type\n" << " -dev.tia.type <standard|custom| Selects a TIA type\n"
<< " koolaidman|\n" << " koolaidman|\n"

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,6 @@ class Cartridge;
#ifdef RETRON77 #ifdef RETRON77
#define UNSAFE_OPTIMIZATIONS #define UNSAFE_OPTIMIZATIONS
#define NO_THUMB_STATS
#endif #endif
#define ROMADDMASK 0x7FFFF #define ROMADDMASK 0x7FFFF
@ -46,8 +45,16 @@ class Cartridge;
#define CPSR_C (1u<<29) #define CPSR_C (1u<<29)
#define CPSR_V (1u<<28) #define CPSR_V (1u<<28)
#define TIMER_0 // enable timer 0 support #ifdef DEBUGGER_SUPPORT
//#define COUNT_OPS #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 class Thumbulator
{ {
@ -62,11 +69,24 @@ class Thumbulator
CDFJplus, // cartridges of type CDFJ+ CDFJplus, // cartridges of type CDFJ+
DPCplus // cartridges of type DPC+ 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 { struct Stats {
#ifndef NO_THUMB_STATS uInt32 instructions{0};
uInt32 fetches{0}, reads{0}, writes{0}; #ifdef THUMB_STATS
uInt32 cycles{0}; uInt32 reads{0}, writes{0};
#endif #endif
}; };
@ -86,10 +106,23 @@ class Thumbulator
*/ */
string doRun(uInt32& cycles); string doRun(uInt32& cycles);
string run(uInt32& cycles); string run(uInt32& cycles);
void enableCycleCount(bool enable) { _countCycles = enable; }
const Stats& stats() const { return _stats; } 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 Normally when a fatal error is encountered, the ARM emulation
immediately throws an exception and exits. This method allows execution 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 @param enable Enable (the default) or disable exceptions on fatal errors
*/ */
static void trapFatalErrors(bool enable) { trapOnFatal = enable; } void trapFatalErrors(bool enable) { trapOnFatal = enable; }
#endif #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
/** /**
Inform the Thumbulator class about the console currently in use, Inform the Thumbulator class about the console currently in use,
@ -171,16 +197,24 @@ class Thumbulator
uxth, uxth,
numOps numOps
}; };
#ifdef THUMB_CYCLE_COUNT
enum class CycleType {
S, N, I // Sequential, Non-sequential, Internal
};
enum class AccessType {
prefetch, branch, data
};
#endif
private: private:
uInt32 read_register(uInt32 reg); 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 fetch16(uInt32 addr);
uInt32 read16(uInt32 addr); uInt32 read16(uInt32 addr);
uInt32 read32(uInt32 addr); uInt32 read32(uInt32 addr);
#ifndef UNSAFE_OPTIMIZATIONS #ifndef UNSAFE_OPTIMIZATIONS
bool isProtected(uInt32 addr); bool isProtected(uInt32 addr);
#endif #endif
void write16(uInt32 addr, uInt32 data); void write16(uInt32 addr, uInt32 data);
void write32(uInt32 addr, uInt32 data); void write32(uInt32 addr, uInt32 data);
void updateTimer(uInt32 cycles); void updateTimer(uInt32 cycles);
@ -194,7 +228,7 @@ class Thumbulator
void do_cflag_bit(uInt32 x); void do_cflag_bit(uInt32 x);
void do_vflag_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 // Throw a runtime_error exception containing an error referencing the
// given message and variables // given message and variables
// Note that the return value is never used in these methods // Note that the return value is never used in these methods
@ -203,10 +237,18 @@ class Thumbulator
void dump_counters(); void dump_counters();
void dump_regs(); void dump_regs();
#endif #endif
int execute(); int execute();
int reset(); 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: private:
const uInt16* rom{nullptr}; const uInt16* rom{nullptr};
uInt32 romSize{0}; uInt32 romSize{0};
@ -216,16 +258,17 @@ class Thumbulator
const unique_ptr<Op[]> decodedRom; // NOLINT const unique_ptr<Op[]> decodedRom; // NOLINT
uInt16* ram{nullptr}; uInt16* ram{nullptr};
std::array<uInt32, 16> reg_norm; // normal execution mode, do not have a thread mode 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}; bool handler_mode{false};
uInt32 systick_ctrl{0}, systick_reload{0}, systick_count{0}, systick_calibrate{0}; uInt32 systick_ctrl{0}, systick_reload{0}, systick_count{0}, systick_calibrate{0};
#ifndef UNSAFE_OPTIMIZATIONS ChipType _chipType{ChipType::LPC2103};
uInt32 instructions{0}; ConsoleTiming _consoleTiming{ConsoleTiming::ntsc};
#endif double _MHz{70.0};
#ifndef NO_THUMB_STATS uInt32 _flashCycles{4};
Stats _stats; uInt32 _flashBanks{1};
Stats _prevStats; Stats _stats{0};
#endif uInt32 _totalCycles{0};
// For emulation of LPC2103's timer 1, used for NTSC/PAL/SECAM detection. // For emulation of LPC2103's timer 1, used for NTSC/PAL/SECAM detection.
// Register names from documentation: // Register names from documentation:
@ -240,17 +283,34 @@ class Thumbulator
uInt32 tim1Cycles{0}; uInt32 tim1Cycles{0};
double timing_factor{0.0}; double timing_factor{0.0};
#ifndef UNSAFE_OPTIMIZATIONS #ifndef UNSAFE_OPTIMIZATIONS
ostringstream statusMsg; 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; bool _countCycles{false};
#endif bool _lockMamcr{false};
#ifndef NO_THUMB_STATS
static double arm_cycle_factor; #ifdef THUMB_CYCLE_COUNT
#endif double _armCyclesFactor{0.90};
#ifdef COUNT_OPS 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}; uInt32 opCount[size_t(Op::numOps)]{0};
#endif #endif
ConfigureFor configuration; ConfigureFor configuration;

View File

@ -740,8 +740,7 @@ void VideoAudioDialog::saveConfig()
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// TV Effects tab // TV Effects tab
// TV Mode // TV Mode
settings.setValue("tv.filter", settings.setValue("tv.filter", myTVMode->getSelectedTag().toString());
myTVMode->getSelectedTag().toString());
// TV Custom adjustables // TV Custom adjustables
NTSCFilter::Adjustable ntscAdj; NTSCFilter::Adjustable ntscAdj;
ntscAdj.sharpness = myTVSharp->getValue(); ntscAdj.sharpness = myTVSharp->getValue();