Skip to content

Commit

Permalink
New thread modes up and running (configurable in Performance panel).
Browse files Browse the repository at this point in the history
  • Loading branch information
dirkwhoffmann committed Jan 27, 2024
1 parent 5b8fd9d commit c129b22
Show file tree
Hide file tree
Showing 14 changed files with 481 additions and 344 deletions.
4 changes: 4 additions & 0 deletions Emulator/Base/CoreComponentTypes.h
Expand Up @@ -25,6 +25,8 @@ enum_long(OPT)
OPT_WARP_BOOT,
OPT_WARP_MODE,
OPT_SYNC_MODE,
OPT_TIME_SLICES,
OPT_AUTO_FPS,
OPT_PROPOSED_FPS,

// VICII
Expand Down Expand Up @@ -127,6 +129,8 @@ struct OptionEnum : util::Reflection<OptionEnum, Option> {
case OPT_WARP_BOOT: return "WARP_BOOT";
case OPT_WARP_MODE: return "WARP_MODE";
case OPT_SYNC_MODE: return "SYNC_MODE";
case OPT_TIME_SLICES: return "TIME_SLICES";
case OPT_AUTO_FPS: return "AUTO_FPS";
case OPT_PROPOSED_FPS: return "PROPOSED_FPS";

case OPT_VIC_REVISION: return "VIC_REVISION";
Expand Down
4 changes: 3 additions & 1 deletion Emulator/Base/Defaults.cpp
Expand Up @@ -21,7 +21,9 @@ Defaults::Defaults()
{
setFallback(OPT_WARP_BOOT, 0);
setFallback(OPT_WARP_MODE, WARP_NEVER);
setFallback(OPT_SYNC_MODE, SYNC_NATIVE_FPS);
setFallback(OPT_SYNC_MODE, THREAD_ADAPTIVE);
setFallback(OPT_TIME_SLICES, 1);
setFallback(OPT_AUTO_FPS, true);
setFallback(OPT_PROPOSED_FPS, 60);

setFallback(OPT_POWER_GRID, GRID_STABLE_50HZ);
Expand Down
15 changes: 10 additions & 5 deletions Emulator/Base/Thread.cpp
Expand Up @@ -31,7 +31,7 @@ Thread::~Thread()
template <ThreadMode M> void
Thread::execute()
{
if (missing) {
if (missing > 0 || warp) {

trace(TIM_DEBUG, "execute<%s>: %lld us\n", ThreadModeEnum::key(M),
execClock.restart().asMicroseconds());
Expand All @@ -56,11 +56,11 @@ Thread::sleep<THREAD_PERIODIC>()

// Make sure the emulator is still in sync
if ((now - targetTime).asMilliseconds() > 200) {
warn("Emulation is way too slow: %f\n", (now - targetTime).asSeconds());
warn("Emulation is way too slow: %f sec behind\n", (now - targetTime).asSeconds());
resync();
}
if ((targetTime - now).asMilliseconds() > 200) {
warn("Emulation is way too fast: %f\n", (targetTime - now).asSeconds());
warn("Emulation is way too fast: %f sec ahead\n", (targetTime - now).asSeconds());
resync();
}

Expand All @@ -76,7 +76,7 @@ Thread::sleep<THREAD_PULSED>()
// Only proceed if we're not running in warp mode
if (warp) return;

if (missing) {
if (missing > 0) {

// Wake up at the scheduled target time
targetTime.sleepUntil();
Expand All @@ -103,8 +103,13 @@ Thread::sleep<THREAD_PULSED>()

// Start over if the emulator got out of sync
if (std::abs(missing) > 5 * slicesPerFrame()) {

if (missing > 0) {
warn("Emulation is way too slow: %ld time slices behind\n", missing);
} else {
warn("Emulation is way too fast: %ld time slices ahead\n", missing);
}

warn("Emulation is off by %ld SYNC points\n", missing);
resync();
}
}
Expand Down
58 changes: 47 additions & 11 deletions Emulator/Components/C64.cpp
Expand Up @@ -332,7 +332,9 @@ C64::resetConfig()
OPT_WARP_BOOT,
OPT_WARP_MODE,
OPT_SYNC_MODE,
OPT_PROPOSED_FPS
OPT_TIME_SLICES,
OPT_AUTO_FPS,
OPT_PROPOSED_FPS,
};

for (auto &option : options) {
Expand All @@ -358,6 +360,14 @@ C64::getConfigItem(Option option) const

return config.syncMode;

case OPT_TIME_SLICES:

return config.timeSlices;

case OPT_AUTO_FPS:

return config.autoFps;

case OPT_PROPOSED_FPS:

return config.proposedFps;
Expand Down Expand Up @@ -495,14 +505,28 @@ C64::setConfigItem(Option option, i64 value)

case OPT_SYNC_MODE:

if (!SyncModeEnum::isValid(value)) {
throw VC64Error(ERROR_OPT_INVARG, SyncModeEnum::keyList());
if (!ThreadModeEnum::isValid(value)) {
throw VC64Error(ERROR_OPT_INVARG, ThreadModeEnum::keyList());
}

config.syncMode = SyncMode(value);
config.syncMode = ThreadMode(value);
updateClockFrequency();
return;

case OPT_TIME_SLICES:

if (value < 1 || value > 4) {
throw VC64Error(ERROR_OPT_INVARG, "1...4");
}

config.timeSlices = value;
return;

case OPT_AUTO_FPS:

config.autoFps = bool(value);
return;

case OPT_PROPOSED_FPS:

if (value < 25 || value > 120) {
Expand Down Expand Up @@ -552,6 +576,8 @@ C64::configure(Option option, i64 value)
case OPT_WARP_BOOT:
case OPT_WARP_MODE:
case OPT_SYNC_MODE:
case OPT_TIME_SLICES:
case OPT_AUTO_FPS:
case OPT_PROPOSED_FPS:

setConfigItem(option, value);
Expand Down Expand Up @@ -1004,7 +1030,7 @@ C64::setInspectionTarget(InspectionTarget target, Cycle trigger)
ThreadMode
C64::getThreadMode() const
{
return config.syncMode == SYNC_VSYNC ? THREAD_PULSED : THREAD_ADAPTIVE;
return config.syncMode;
}

void
Expand Down Expand Up @@ -1193,9 +1219,14 @@ C64::refreshRate() const
{
switch (config.syncMode) {

case SYNC_NATIVE_FPS: return vic.getFps();
case SYNC_FIXED_FPS: return config.proposedFps;
case SYNC_VSYNC: return host.getHostRefreshRate();
case THREAD_PULSED:

return host.getHostRefreshRate();

case THREAD_PERIODIC:
case THREAD_ADAPTIVE:

return config.autoFps ? vic.getFps() : config.proposedFps;

default:
fatalError;
Expand All @@ -1205,7 +1236,7 @@ C64::refreshRate() const
isize
C64::slicesPerFrame() const
{
return 1;
return config.timeSlices;
}

util::Time
Expand Down Expand Up @@ -1367,8 +1398,13 @@ C64::_dump(Category category, std::ostream& os) const
os << tab("Warp boot");
os << dec(config.warpBoot) << " seconds" << std::endl;
os << tab("Sync mode");
os << SyncModeEnum::key(config.syncMode);
if (config.syncMode == SYNC_FIXED_FPS) os << " (" << config.proposedFps << " fps)";
os << ThreadModeEnum::key(config.syncMode) << std::endl;
os << tab("Time slices");
os << config.timeSlices << std::endl;
os << tab("Auto fps");
os << bol(config.autoFps) << std::endl;
os << tab("Proposed fps");
os << config.proposedFps << " Fps" << std::endl;
os << std::endl;
}

Expand Down
8 changes: 6 additions & 2 deletions Emulator/Components/C64Types.h
Expand Up @@ -14,7 +14,7 @@

#include "Aliases.h"
#include "Reflection.h"

#include "ThreadTypes.h"

//
// Enumerations
Expand Down Expand Up @@ -218,6 +218,7 @@ struct WarpModeEnum : util::Reflection<WarpModeEnum, WarpMode>
};
#endif

/*
enum_long(SYNC_MODE)
{
SYNC_NATIVE_FPS,
Expand Down Expand Up @@ -246,6 +247,7 @@ struct SyncModeEnum : util::Reflection<SyncModeEnum, SyncMode>
}
};
#endif
*/

enum_long(ROM_TYPE)
{
Expand Down Expand Up @@ -326,8 +328,10 @@ typedef struct
{
isize warpBoot;
WarpMode warpMode;
SyncMode syncMode;
ThreadMode syncMode;
bool autoFps;
isize proposedFps;
isize timeSlices;
}
C64Config;

Expand Down
19 changes: 16 additions & 3 deletions Emulator/Misc/RetroShell/InterpreterCmds.cpp
Expand Up @@ -213,19 +213,32 @@ Interpreter::initCommandShell(Command &root)
c64.configure(OPT_WARP_MODE, parseEnum <WarpModeEnum> (argv));
});

root.add({"c64", "set", "syncmode"}, { SyncModeEnum::argList() },
root.add({"c64", "set", "syncmode"}, { ThreadModeEnum::argList() },
"Selects the synchronization mode",
[this](Arguments& argv, long value) {

c64.configure(OPT_SYNC_MODE, parseEnum <SyncModeEnum> (argv));
c64.configure(OPT_SYNC_MODE, parseEnum <ThreadModeEnum> (argv));
});

root.add({"c64", "set", "timeslices"}, { Arg::value },
"Sets how often the thread starts and stops per frame",
[this](Arguments& argv, long value) {

c64.configure(OPT_TIME_SLICES, parseNum(argv));
});

root.add({"c64", "set", "autofps"}, { Arg::boolean },
"Selects whether the refresh rate is determined by the C64 model",
[this](Arguments& argv, long value) {

c64.configure(OPT_AUTO_FPS, parseBool(argv));
});

root.add({"c64", "set", "fps"}, { Arg::value },
"Sets the proposed number of frames per seconds",
[this](Arguments& argv, long value) {

c64.configure(OPT_PROPOSED_FPS, parseNum(argv));
c64.configure(OPT_SYNC_MODE, SYNC_FIXED_FPS);
});

root.add({"c64", "power"}, { Arg::onoff },
Expand Down
13 changes: 13 additions & 0 deletions GUI/Defaults.swift
Expand Up @@ -950,6 +950,10 @@ extension DefaultsProxy {
remove(.SB_COLLISIONS)
remove(.WARP_MODE)
remove(.WARP_BOOT)
remove(.SYNC_MODE)
remove(.AUTO_FPS)
remove(.PROPOSED_FPS)
remove(.TIME_SLICES)
}
}

Expand All @@ -970,6 +974,11 @@ extension Configuration {
defaults.set(.SB_COLLISIONS, sbCollisions)
defaults.set(.WARP_MODE, warpMode)
defaults.set(.WARP_BOOT, warpBoot)
defaults.set(.SYNC_MODE, syncMode)
defaults.set(.AUTO_FPS, autoFps)
defaults.set(.PROPOSED_FPS, proposedFps)
defaults.set(.TIME_SLICES, timeSlices)

defaults.save()

c64.resume()
Expand All @@ -990,6 +999,10 @@ extension Configuration {
sbCollisions = defaults.get(.SB_COLLISIONS) != 0
warpMode = defaults.get(.WARP_MODE)
warpBoot = defaults.get(.WARP_BOOT)
syncMode = defaults.get(.SYNC_MODE)
autoFps = defaults.get(.AUTO_FPS) != 0
proposedFps = defaults.get(.PROPOSED_FPS)
timeSlices = defaults.get(.TIME_SLICES)

c64.resume()
}
Expand Down
54 changes: 53 additions & 1 deletion GUI/Panels/Configuration/CompatibilityConf.swift
Expand Up @@ -24,12 +24,28 @@ extension ConfigurationController {
comWarpMode.selectItem(withTag: config.warpMode)
comWarpBoot.integerValue = config.warpBoot

// Frame rate
let fps = c64.refreshRate
comSyncMode.selectItem(withTag: config.syncMode)
comAutoFps.state = config.autoFps ? .on : .off
comFpsSlider.integerValue = fps
comFpsInfo.stringValue = "\(fps) frames per second"
comSliceSlider.integerValue = config.timeSlices
comSliceInfo.stringValue = "\(config.timeSlices) time slices per frame"
comAutoFps.isEnabled = config.syncMode != 1
comFpsSlider.isEnabled = config.syncMode != 1 && !config.autoFps
comFpsInfo.isEnabled = config.syncMode != 1

// Power button
comPowerButton.isHidden = !bootable
}

//
// Action methods (power saving)
//

@IBAction func comDrivePowerSaveAction(_ sender: NSButton!) {

config.drive8PowerSave = sender.state == .on
config.drive9PowerSave = sender.state == .on
refresh()
Expand All @@ -47,6 +63,10 @@ extension ConfigurationController {
refresh()
}

//
// Action methods (collision detection)
//

@IBAction func comSsCollisionsAction(_ sender: NSButton!) {

config.ssCollisions = sender.state == .on
Expand All @@ -59,6 +79,10 @@ extension ConfigurationController {
refresh()
}

//
// Action methods (warp)
//

@IBAction func comWarpModeAction(_ sender: NSPopUpButton!) {

config.warpMode = sender.selectedTag()
Expand All @@ -71,6 +95,34 @@ extension ConfigurationController {
refresh()
}

//
// Action methods (threading)
//

@IBAction func comSyncModeAction(_ sender: NSPopUpButton!) {

config.syncMode = sender.selectedTag()
refresh()
}

@IBAction func comTimeSlicesAction(_ sender: NSSlider!) {

config.timeSlices = sender.integerValue
refresh()
}

@IBAction func comAutoFpsAction(_ sender: NSButton!) {

config.autoFps = sender.state == .on
refresh()
}

@IBAction func comFpsAction(_ sender: NSSlider!) {

config.proposedFps = sender.integerValue
refresh()
}

@IBAction func comPresetAction(_ sender: NSPopUpButton!) {

c64.suspend()
Expand Down

0 comments on commit c129b22

Please sign in to comment.