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>
</tr><tr>
<td><pre>-dev.thumb.incycles &lt;1|0&gt;</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 &lt;float&gt;</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 &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>
<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

View File

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

View File

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

View File

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

View File

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

View File

@ -112,6 +112,8 @@ void CartridgeBUS::setInitialState()
mySTYZeroPageAddress = myJMPoperandAddress = 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
*/
void setInitialState();
void setInitialState() override;
/**
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;
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
*/
void setInitialState();
void setInitialState() override;
/**
Updates any data fetchers in music mode based on the number of

View File

@ -118,6 +118,8 @@ void CartridgeDPCPlus::setInitialState()
myFastFetch = myLDAimmediate = false;
myAudioCycles = myARMCycles = 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
*/
void setInitialState();
void setInitialState() override;
/**
Clocks the random number generator to move it to its next state

View File

@ -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
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -685,8 +689,13 @@ void Settings::usage() const
#endif
<< " -dev.thumb.trapfatal <1|0> Determines whether errors in ARM emulation\n"
<< " throw an exception\n"
#ifdef DEBUGGER_SUPPORT
<< " -dev.thumb.inccycles <1|0> Determines whether ARM emulation cycles\n"
<< " increase system cycles\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"

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -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();