diff --git a/src/emucore/OSystem.hxx b/src/emucore/OSystem.hxx
index f54f59171..5d132920b 100644
--- a/src/emucore/OSystem.hxx
+++ b/src/emucore/OSystem.hxx
@@ -598,6 +598,9 @@ class OSystem
     // Indicates whether to stop the main loop
     bool myQuitLoop{false};
 
+    static constexpr uInt32 FPS_METER_QUEUE_SIZE = 100;
+    FpsMeter myFpsMeter{FPS_METER_QUEUE_SIZE};
+
   private:
     FSNode myBaseDir, myStateDir, mySnapshotSaveDir, mySnapshotLoadDir,
            myNVRamDir, myCfgDir, myHomeDir, myUserDir, myBezelDir;
@@ -607,9 +610,6 @@ class OSystem
     string myFeatures;
     string myBuildInfo;
 
-    static constexpr uInt32 FPS_METER_QUEUE_SIZE = 100;
-    FpsMeter myFpsMeter{FPS_METER_QUEUE_SIZE};
-
     // If not empty, a hint for derived classes to use this as the
     // base directory (where all settings are stored)
     // Derived classes are free to ignore it and use their own defaults
diff --git a/src/os/rtstella/OSystemRTStella.cxx b/src/os/rtstella/OSystemRTStella.cxx
index 0b95f3339..d674a3a64 100644
--- a/src/os/rtstella/OSystemRTStella.cxx
+++ b/src/os/rtstella/OSystemRTStella.cxx
@@ -5,6 +5,13 @@
 #include <sys/sysinfo.h>
 
 #include "Logger.hxx"
+#include "RTEmulationWorker.hxx"
+#include "EventHandler.hxx"
+#include "TimerManager.hxx"
+#include "DispatchResult.hxx"
+#include "Console.hxx"
+#include "Debugger.hxx"
+#include "TIA.hxx"
 
 namespace {
   void configureScheduler() {
@@ -34,3 +41,73 @@ bool OSystemRTStella::initialize(const Settings::Options& options)
 
   return OSystemStandalone::initialize(options);
 }
+
+void OSystemRTStella::mainLoop()
+{
+  RTEmulationWorker worker;
+  DispatchResult dispatchResult;
+
+  for (;;) {
+    TIA& tia = myConsole->tia();
+
+    if (worker.isRunning()) worker.suspend();
+
+    const EventHandlerState oldState = myEventHandler->state();
+    const bool workerWasRunning = worker.isRunning();
+
+    if (oldState == EventHandlerState::EMULATION && worker.isRunning()) {
+      tia.renderToFrameBuffer();
+
+      switch (dispatchResult.getStatus()) {
+        case DispatchResult::Status::ok:
+        break;
+
+        case DispatchResult::Status::debugger:
+          #ifdef DEBUGGER_SUPPORT
+           myDebugger->start(
+              dispatchResult.getMessage(),
+              dispatchResult.getAddress(),
+              dispatchResult.wasReadTrap(),
+              dispatchResult.getToolTip()
+            );
+          #endif
+
+          break;
+
+        case DispatchResult::Status::fatal:
+          #ifdef DEBUGGER_SUPPORT
+            myDebugger->startWithFatalError(dispatchResult.getMessage());
+          #else
+            cerr << dispatchResult.getMessage() << endl;
+          #endif
+            break;
+
+        default:
+          cout << (int)dispatchResult.getStatus() << endl << std::flush;
+          throw runtime_error("invalid emulation dispatch result");
+      }
+    }
+
+    myEventHandler->poll(TimerManager::getTicks());
+    if (myQuitLoop) break;
+
+    if (dispatchResult.getStatus() == DispatchResult::Status::ok && myEventHandler->frying() && worker.isRunning())
+      myConsole->fry();
+
+    const EventHandlerState newState = myEventHandler->state();
+
+    if (newState == EventHandlerState::EMULATION && !worker.isRunning()) {
+      worker.start(myConsole->emulationTiming().cyclesPerSecond(), &dispatchResult, &tia);
+      myFpsMeter.reset();
+    } else if (newState != EventHandlerState::EMULATION && worker.isRunning()) {
+      worker.stop();
+    } else if (newState == EventHandlerState::EMULATION && worker.isRunning()) {
+      worker.resume();
+    }
+
+    if (oldState == EventHandlerState::EMULATION && workerWasRunning)
+      myFrameBuffer->updateInEmulationMode(myFpsMeter.fps());
+    else
+      myFrameBuffer->update();
+  }
+}
diff --git a/src/os/rtstella/OSystemRTStella.hxx b/src/os/rtstella/OSystemRTStella.hxx
index 72e1abe80..07b510da0 100644
--- a/src/os/rtstella/OSystemRTStella.hxx
+++ b/src/os/rtstella/OSystemRTStella.hxx
@@ -23,6 +23,8 @@
 class OSystemRTStella: public OSystemStandalone {
   public:
     bool initialize(const Settings::Options& options) override;
+
+    void mainLoop() override;
 };
 
 #endif // OSYSTEM_RTSTELLA_HXX
diff --git a/src/os/rtstella/RTEmulationWorker.cxx b/src/os/rtstella/RTEmulationWorker.cxx
index 3a6cd22f8..5498b096f 100644
--- a/src/os/rtstella/RTEmulationWorker.cxx
+++ b/src/os/rtstella/RTEmulationWorker.cxx
@@ -15,12 +15,15 @@
 #define TRACE_MSG(m) m " in " STRINGIFY(__FILE__) ":" STRINGIFY(__LINE__)
 
 namespace {
-  constexpr uint64_t TIMESLICE_NANOSECONDS = 100000;
-  constexpr uint64_t MAX_LAG_NANOSECONDS = 10 * TIMESLICE_NANOSECONDS;
+  constexpr uint64_t TIMESLICE_NANOSECONDS = 1000000;
+  constexpr uint64_t MAX_LAG_NANOSECONDS = 100000000;
 
   inline Int64 timeDifferenceNanoseconds(const struct timespec& from, const struct timespec& to)
   {
-    return (from.tv_sec - to.tv_sec) * 1000000000 + (from.tv_nsec - to.tv_nsec);
+    uInt64 deltaSec = from.tv_sec - to.tv_sec;
+    uInt64 deltaNsec = from.tv_nsec - to.tv_nsec;
+
+    return deltaSec * 1000000000 + deltaNsec;
   }
 
   void configureScheduler() {
@@ -119,6 +122,8 @@ void RTEmulationWorker::suspend()
 
   // the thread may transition to State::exception instead, so make sure that we rethrow
   while (myState != State::paused) rethrowPendingException();
+
+  __sync_synchronize();
 }
 
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -133,6 +138,8 @@ void RTEmulationWorker::resume()
 
   // the thread may transition to State::exception instead, so make sure that we rethrow
   while (myState != State::running) rethrowPendingException();
+
+  __sync_synchronize();
 }
 
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -207,6 +214,7 @@ void RTEmulationWorker::stop()
   }
 }
 
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 void RTEmulationWorker::threadMain()
 {
   configureScheduler();
@@ -260,6 +268,8 @@ void RTEmulationWorker::dispatchEmulation()
 
   clock_gettime(CLOCK_MONOTONIC, &timeOffset);
 
+  myDispatchResult->setOk(0);
+
   myState = State::running;
   myPendingSignal = Signal::none;
 
diff --git a/src/os/rtstella/RTEmulationWorker.hxx b/src/os/rtstella/RTEmulationWorker.hxx
index 2c211861c..74533fb2d 100644
--- a/src/os/rtstella/RTEmulationWorker.hxx
+++ b/src/os/rtstella/RTEmulationWorker.hxx
@@ -64,6 +64,16 @@ class RTEmulationWorker {
 
     void stop();
 
+    State state()
+    {
+      return myState;
+    }
+
+    bool isRunning()
+    {
+      return myState == State::running || myState == State::paused;
+    }
+
   private:
 
     void threadMain();