From c129b228f983349c74f7e33a14def10326c0d6cb Mon Sep 17 00:00:00 2001 From: Dirk Hoffmann Date: Sat, 27 Jan 2024 13:47:58 +0100 Subject: [PATCH] New thread modes up and running (configurable in Performance panel). --- Emulator/Base/CoreComponentTypes.h | 4 + Emulator/Base/Defaults.cpp | 4 +- Emulator/Base/Thread.cpp | 15 +- Emulator/Components/C64.cpp | 58 +- Emulator/Components/C64Types.h | 8 +- Emulator/Misc/RetroShell/InterpreterCmds.cpp | 19 +- GUI/Defaults.swift | 13 + .../Configuration/CompatibilityConf.swift | 54 +- GUI/Panels/Configuration/Configuration.swift | 30 +- .../ConfigurationController.swift | 16 +- GUI/Panels/Configuration/VideoConf.swift | 26 - GUI/XIB files/Configuration.xib | 571 +++++++++--------- Proxy/C64Proxy.h | 2 + Proxy/C64Proxy.mm | 5 + 14 files changed, 481 insertions(+), 344 deletions(-) diff --git a/Emulator/Base/CoreComponentTypes.h b/Emulator/Base/CoreComponentTypes.h index aa1973862..b7e68b5ab 100644 --- a/Emulator/Base/CoreComponentTypes.h +++ b/Emulator/Base/CoreComponentTypes.h @@ -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 @@ -127,6 +129,8 @@ struct OptionEnum : util::Reflection { 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"; diff --git a/Emulator/Base/Defaults.cpp b/Emulator/Base/Defaults.cpp index 6a4ce916b..7295e96b4 100644 --- a/Emulator/Base/Defaults.cpp +++ b/Emulator/Base/Defaults.cpp @@ -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); diff --git a/Emulator/Base/Thread.cpp b/Emulator/Base/Thread.cpp index 02bea47d3..ef2d393cf 100644 --- a/Emulator/Base/Thread.cpp +++ b/Emulator/Base/Thread.cpp @@ -31,7 +31,7 @@ Thread::~Thread() template void Thread::execute() { - if (missing) { + if (missing > 0 || warp) { trace(TIM_DEBUG, "execute<%s>: %lld us\n", ThreadModeEnum::key(M), execClock.restart().asMicroseconds()); @@ -56,11 +56,11 @@ Thread::sleep() // 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(); } @@ -76,7 +76,7 @@ Thread::sleep() // 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(); @@ -103,8 +103,13 @@ Thread::sleep() // 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(); } } diff --git a/Emulator/Components/C64.cpp b/Emulator/Components/C64.cpp index 34665d785..2c8f68c02 100644 --- a/Emulator/Components/C64.cpp +++ b/Emulator/Components/C64.cpp @@ -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) { @@ -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; @@ -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) { @@ -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); @@ -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 @@ -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; @@ -1205,7 +1236,7 @@ C64::refreshRate() const isize C64::slicesPerFrame() const { - return 1; + return config.timeSlices; } util::Time @@ -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; } diff --git a/Emulator/Components/C64Types.h b/Emulator/Components/C64Types.h index 72553e2f8..4afa87e69 100644 --- a/Emulator/Components/C64Types.h +++ b/Emulator/Components/C64Types.h @@ -14,7 +14,7 @@ #include "Aliases.h" #include "Reflection.h" - +#include "ThreadTypes.h" // // Enumerations @@ -218,6 +218,7 @@ struct WarpModeEnum : util::Reflection }; #endif +/* enum_long(SYNC_MODE) { SYNC_NATIVE_FPS, @@ -246,6 +247,7 @@ struct SyncModeEnum : util::Reflection } }; #endif +*/ enum_long(ROM_TYPE) { @@ -326,8 +328,10 @@ typedef struct { isize warpBoot; WarpMode warpMode; - SyncMode syncMode; + ThreadMode syncMode; + bool autoFps; isize proposedFps; + isize timeSlices; } C64Config; diff --git a/Emulator/Misc/RetroShell/InterpreterCmds.cpp b/Emulator/Misc/RetroShell/InterpreterCmds.cpp index 87750c4ad..f89b5da7b 100644 --- a/Emulator/Misc/RetroShell/InterpreterCmds.cpp +++ b/Emulator/Misc/RetroShell/InterpreterCmds.cpp @@ -213,11 +213,25 @@ Interpreter::initCommandShell(Command &root) c64.configure(OPT_WARP_MODE, parseEnum (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 (argv)); + c64.configure(OPT_SYNC_MODE, parseEnum (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 }, @@ -225,7 +239,6 @@ Interpreter::initCommandShell(Command &root) [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 }, diff --git a/GUI/Defaults.swift b/GUI/Defaults.swift index f216eeee9..b2e40fdc0 100644 --- a/GUI/Defaults.swift +++ b/GUI/Defaults.swift @@ -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) } } @@ -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() @@ -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() } diff --git a/GUI/Panels/Configuration/CompatibilityConf.swift b/GUI/Panels/Configuration/CompatibilityConf.swift index 39ce57bb6..e61416ae3 100644 --- a/GUI/Panels/Configuration/CompatibilityConf.swift +++ b/GUI/Panels/Configuration/CompatibilityConf.swift @@ -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() @@ -47,6 +63,10 @@ extension ConfigurationController { refresh() } + // + // Action methods (collision detection) + // + @IBAction func comSsCollisionsAction(_ sender: NSButton!) { config.ssCollisions = sender.state == .on @@ -59,6 +79,10 @@ extension ConfigurationController { refresh() } + // + // Action methods (warp) + // + @IBAction func comWarpModeAction(_ sender: NSPopUpButton!) { config.warpMode = sender.selectedTag() @@ -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() diff --git a/GUI/Panels/Configuration/Configuration.swift b/GUI/Panels/Configuration/Configuration.swift index 08d2b0800..53746633f 100644 --- a/GUI/Panels/Configuration/Configuration.swift +++ b/GUI/Panels/Configuration/Configuration.swift @@ -198,7 +198,7 @@ class Configuration { } // - // Performance (formerly called Compatibility) + // Performance // var drive8PowerSave: Bool { @@ -241,6 +241,26 @@ class Configuration { set { c64.configure(.WARP_BOOT, value: newValue) } } + var syncMode: Int { + get { return c64.getConfig(.SYNC_MODE) } + set { c64.configure(.SYNC_MODE, value: newValue) } + } + + var timeSlices: Int { + get { return c64.getConfig(.TIME_SLICES) } + set { c64.configure(.TIME_SLICES, value: newValue) } + } + + var autoFps: Bool { + get { return c64.getConfig(.AUTO_FPS) != 0 } + set { c64.configure(.AUTO_FPS, enable: newValue) } + } + + var proposedFps: Int { + get { return c64.getConfig(.PROPOSED_FPS) } + set { c64.configure(.PROPOSED_FPS, value: newValue) } + } + // // Audio // @@ -342,14 +362,6 @@ class Configuration { // Video // - var syncMode: Int { - get { return c64.getConfig(.SYNC_MODE) } - set { c64.configure(.SYNC_MODE, value: newValue) } - } - var proposedFps: Int { - get { return c64.getConfig(.PROPOSED_FPS) } - set { c64.configure(.PROPOSED_FPS, value: newValue) } - } var palette: Int { get { return c64.getConfig(.PALETTE) } set { c64.configure(.PALETTE, value: newValue) } diff --git a/GUI/Panels/Configuration/ConfigurationController.swift b/GUI/Panels/Configuration/ConfigurationController.swift index 133d86e24..22a149b26 100644 --- a/GUI/Panels/Configuration/ConfigurationController.swift +++ b/GUI/Panels/Configuration/ConfigurationController.swift @@ -117,7 +117,7 @@ class ConfigurationController: DialogController { @IBOutlet weak var perPowerButton: NSButton! // - // Performance (formerly called Compatibility) + // Performance // // Power saving @@ -133,6 +133,14 @@ class ConfigurationController: DialogController { @IBOutlet weak var comWarpMode: NSPopUpButton! @IBOutlet weak var comWarpBoot: NSTextField! + // Threading + @IBOutlet weak var comSyncMode: NSPopUpButton! + @IBOutlet weak var comAutoFps: NSButton! + @IBOutlet weak var comFpsSlider: NSSlider! + @IBOutlet weak var comFpsInfo: NSTextField! + @IBOutlet weak var comSliceSlider: NSSlider! + @IBOutlet weak var comSliceInfo: NSTextField! + // Buttons @IBOutlet weak var comPowerButton: NSButton! @@ -192,12 +200,6 @@ class ConfigurationController: DialogController { @IBOutlet weak var vidHCenterLabel: NSTextField! @IBOutlet weak var vidVCenterLabel: NSTextField! - // Frame rate - @IBOutlet weak var vidSyncMode: NSPopUpButton! - @IBOutlet weak var vidFpsSlider: NSSlider! - @IBOutlet weak var vidFpsMin: NSTextField! - @IBOutlet weak var vidFpsMax: NSTextField! - // Effects @IBOutlet weak var vidUpscalerPopUp: NSPopUpButton! @IBOutlet weak var vidBlurPopUp: NSPopUpButton! diff --git a/GUI/Panels/Configuration/VideoConf.swift b/GUI/Panels/Configuration/VideoConf.swift index 505b7ac9e..e332d5335 100644 --- a/GUI/Panels/Configuration/VideoConf.swift +++ b/GUI/Panels/Configuration/VideoConf.swift @@ -50,16 +50,6 @@ extension ConfigurationController { vidHCenterLabel.textColor = .labelColor vidVCenterLabel.textColor = .labelColor - // Frame rate - let syncMode = config.syncMode - let fps = config.proposedFps - vidSyncMode.item(at: 1)?.title = "Fixed (\(fps) fps)" - vidSyncMode.selectItem(withTag: syncMode) - vidFpsSlider.integerValue = fps - vidFpsSlider.isHidden = syncMode != 1 - vidFpsMin.isHidden = syncMode != 1 - vidFpsMax.isHidden = syncMode != 1 - // Upscalers vidUpscalerPopUp.selectItem(withTag: config.upscaler) @@ -158,22 +148,6 @@ extension ConfigurationController { refresh() } - // - // Action methods (Refresh rate) - // - - @IBAction func vidSyncModeAction(_ sender: NSPopUpButton!) { - - config.syncMode = sender.selectedTag() - refresh() - } - - @IBAction func vidFpsAction(_ sender: NSSlider!) { - - config.proposedFps = sender.integerValue - refresh() - } - // // Action methods (Effects) // diff --git a/GUI/XIB files/Configuration.xib b/GUI/XIB files/Configuration.xib index fa9bba4d9..7215993d7 100644 --- a/GUI/XIB files/Configuration.xib +++ b/GUI/XIB files/Configuration.xib @@ -1,8 +1,8 @@ - + - + @@ -38,11 +38,17 @@ + + + + + + @@ -109,9 +115,6 @@ - - - @@ -126,7 +129,6 @@ - @@ -256,7 +258,7 @@ Gw - + @@ -265,7 +267,7 @@ Gw - + @@ -274,7 +276,7 @@ Gw - + @@ -294,7 +296,7 @@ Gw - + @@ -303,7 +305,7 @@ Gw - + @@ -323,7 +325,7 @@ Gw - + @@ -332,7 +334,7 @@ Gw - + @@ -341,7 +343,7 @@ Gw - + @@ -361,7 +363,7 @@ Gw - + @@ -370,7 +372,7 @@ Gw - + @@ -379,7 +381,7 @@ Gw - + @@ -388,7 +390,7 @@ Gw - + @@ -416,7 +418,7 @@ Gw - + @@ -425,7 +427,7 @@ Gw - + @@ -478,7 +480,7 @@ DQ - + @@ -627,7 +629,7 @@ Gw - + @@ -636,7 +638,7 @@ Gw - + @@ -645,7 +647,7 @@ Gw - + @@ -657,7 +659,7 @@ Gw - - + @@ -680,7 +682,7 @@ Gw - - + @@ -703,7 +705,7 @@ Gw - - + @@ -747,7 +749,7 @@ Gw - + @@ -756,7 +758,7 @@ Gw - + @@ -765,7 +767,7 @@ Gw - + @@ -796,7 +798,7 @@ Gw - + @@ -805,7 +807,7 @@ Gw - + @@ -835,7 +837,7 @@ Gw - + @@ -844,7 +846,7 @@ Gw - + @@ -869,7 +871,7 @@ Gw - + @@ -899,7 +901,7 @@ Gw - + @@ -916,7 +918,7 @@ Gw - + @@ -940,7 +942,7 @@ Gw - + @@ -1025,7 +1027,7 @@ Gw - + @@ -1049,7 +1051,7 @@ Gw - + @@ -1058,7 +1060,7 @@ Gw - + @@ -1082,7 +1084,7 @@ Gw - + @@ -1091,7 +1093,7 @@ Gw - + @@ -1100,7 +1102,7 @@ Gw - + @@ -1118,7 +1120,7 @@ Gw - + @@ -1127,7 +1129,7 @@ Gw - + @@ -1151,7 +1153,7 @@ Gw - + @@ -1160,7 +1162,7 @@ Gw - + @@ -1178,7 +1180,7 @@ Gw - + @@ -1187,7 +1189,7 @@ Gw - + @@ -1196,7 +1198,7 @@ Gw - - - + @@ -1239,7 +1241,7 @@ Gw - + @@ -1248,7 +1250,7 @@ Gw - + @@ -1281,7 +1283,7 @@ Gw - + @@ -1314,7 +1316,7 @@ Gw - + @@ -1323,7 +1325,7 @@ Gw - + @@ -1332,7 +1334,7 @@ Gw - + @@ -1365,7 +1367,7 @@ Gw - + @@ -1374,7 +1376,7 @@ Gw - + @@ -1392,7 +1394,7 @@ Gw - + @@ -1401,7 +1403,7 @@ Gw - - + @@ -1499,8 +1501,17 @@ Gw - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -1568,8 +1552,8 @@ Gw - - + + @@ -1578,7 +1562,7 @@ Gw - + @@ -1601,7 +1585,49 @@ Gw - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1610,8 +1636,8 @@ Gw - - + + @@ -1622,8 +1648,8 @@ Gw - - + + @@ -1631,7 +1657,7 @@ Gw - + @@ -1641,7 +1667,7 @@ Gw + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1677,7 +1757,7 @@ Gw - + @@ -1686,7 +1766,7 @@ Gw - + @@ -1695,7 +1775,7 @@ Gw - + @@ -1704,7 +1784,7 @@ Gw - + @@ -1713,7 +1793,7 @@ Gw - + @@ -1722,7 +1802,7 @@ Gw - + @@ -1731,7 +1811,7 @@ Gw - + @@ -1740,7 +1820,7 @@ Gw - + @@ -1757,7 +1837,7 @@ Gw - + @@ -1766,7 +1846,7 @@ Gw - + @@ -1775,7 +1855,7 @@ Gw - + @@ -1792,7 +1872,7 @@ Gw - + @@ -1801,7 +1881,7 @@ Gw - + @@ -1810,7 +1890,7 @@ Gw - + @@ -1835,7 +1915,7 @@ Gw - + @@ -1844,7 +1924,7 @@ Gw - + @@ -1861,7 +1941,7 @@ Gw - + @@ -1870,7 +1950,7 @@ Gw - + @@ -1962,7 +2042,7 @@ Gw - + @@ -1971,7 +2051,7 @@ Gw - + @@ -1980,7 +2060,7 @@ Gw - + @@ -1989,7 +2069,7 @@ Gw - + @@ -1998,7 +2078,7 @@ Gw - + @@ -2007,7 +2087,7 @@ Gw - + @@ -2016,7 +2096,7 @@ Gw - + @@ -2025,7 +2105,7 @@ Gw - + @@ -2034,7 +2114,7 @@ Gw - + @@ -2043,7 +2123,7 @@ Gw - + @@ -2052,7 +2132,7 @@ Gw - + @@ -2061,7 +2141,7 @@ Gw - + @@ -2070,7 +2150,7 @@ Gw - + @@ -2079,7 +2159,7 @@ Gw - + @@ -2088,7 +2168,7 @@ Gw - + @@ -2097,7 +2177,7 @@ Gw - + @@ -2114,7 +2194,7 @@ Gw - + @@ -2123,7 +2203,7 @@ Gw - + @@ -2140,7 +2220,7 @@ Gw - + @@ -2149,7 +2229,7 @@ Gw - + @@ -2166,7 +2246,7 @@ Gw - + @@ -2175,7 +2255,7 @@ Gw - + @@ -2192,7 +2272,7 @@ Gw - + @@ -2201,7 +2281,7 @@ Gw - + @@ -2252,7 +2332,7 @@ Gw - + @@ -2261,7 +2341,7 @@ Gw - + @@ -2270,7 +2350,7 @@ Gw - + @@ -2279,7 +2359,7 @@ Gw - + @@ -2288,7 +2368,7 @@ Gw - + @@ -2305,7 +2385,7 @@ Gw - + @@ -2314,7 +2394,7 @@ Gw - + @@ -2323,7 +2403,7 @@ Gw - + @@ -2392,7 +2472,7 @@ Gw - + @@ -2401,7 +2481,7 @@ Gw - + @@ -2538,8 +2618,8 @@ Gw - - + + @@ -2547,8 +2627,8 @@ Gw - - + + @@ -2556,8 +2636,8 @@ Gw - - + + @@ -2566,7 +2646,7 @@ Gw - + @@ -2598,8 +2678,8 @@ Gw - - + + @@ -2607,8 +2687,8 @@ Gw - - + + @@ -2616,8 +2696,8 @@ Gw - - + + @@ -2626,7 +2706,7 @@ Gw - + @@ -2634,7 +2714,7 @@ Gw - + @@ -2642,15 +2722,15 @@ Gw - + - - + + @@ -2659,7 +2739,7 @@ Gw - + @@ -2667,15 +2747,15 @@ Gw - + - - + + @@ -2683,8 +2763,8 @@ Gw - - + + @@ -2692,8 +2772,8 @@ Gw - - + + @@ -2702,7 +2782,7 @@ Gw - + @@ -2710,7 +2790,7 @@ Gw - + @@ -2718,7 +2798,7 @@ Gw - + @@ -2731,7 +2811,7 @@ Gw - + @@ -2743,73 +2823,6 @@ Gw - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2818,7 +2831,7 @@ Gw - + @@ -2851,7 +2864,7 @@ Gw - + @@ -2897,7 +2910,7 @@ Gw - + @@ -2906,7 +2919,7 @@ Gw - + @@ -2915,7 +2928,7 @@ Gw - + @@ -2924,7 +2937,7 @@ Gw - + @@ -2962,7 +2975,7 @@ Gw - + @@ -3009,7 +3022,7 @@ Gw - + @@ -3018,7 +3031,7 @@ Gw - + @@ -3027,7 +3040,7 @@ Gw - + @@ -3068,7 +3081,7 @@ Gw - + @@ -3085,7 +3098,7 @@ Gw - + @@ -3139,7 +3152,7 @@ Gw - + @@ -3148,7 +3161,7 @@ Gw - + @@ -3157,7 +3170,7 @@ Gw - + @@ -3174,7 +3187,7 @@ Gw - + @@ -3191,7 +3204,7 @@ Gw - + diff --git a/Proxy/C64Proxy.h b/Proxy/C64Proxy.h index 667f00366..6b4e5d340 100644 --- a/Proxy/C64Proxy.h +++ b/Proxy/C64Proxy.h @@ -220,6 +220,8 @@ @property (readonly) SnapshotProxy *latestAutoSnapshot; @property (readonly) SnapshotProxy *latestUserSnapshot; +@property (readonly) NSInteger refreshRate; + - (NSInteger)getConfig:(Option)opt; - (NSInteger)getConfig:(Option)opt id:(NSInteger)id; - (NSInteger)getConfig:(Option)opt drive:(NSInteger)id; diff --git a/Proxy/C64Proxy.mm b/Proxy/C64Proxy.mm index ee9bea43f..3ad4ab5dc 100644 --- a/Proxy/C64Proxy.mm +++ b/Proxy/C64Proxy.mm @@ -2781,6 +2781,11 @@ - (SnapshotProxy *)latestUserSnapshot return [SnapshotProxy make:snapshot]; } +- (NSInteger)refreshRate +{ + return (NSInteger)[self c64]->refreshRate(); +} + - (NSInteger)getConfig:(Option)opt { return [self c64]->getConfigItem(opt);