From dc9b460f366e700f5ea908f5fd933a048be4f08f Mon Sep 17 00:00:00 2001
From: Lars Immisch <lars@ibp.de>
Date: Sat, 21 Apr 2012 03:06:38 +0200
Subject: [PATCH] Make Step stoppable, print less when used as a library.

This patch fixes two problems:
- SystemClock::Step didn't honour Stop, so if Stop was called internally
  from a device (because an exit symbol was encountered), a loop with Step
  would never terminate. This was a problem in the existing example code,
  e.g. examples/python/ex_utils.py#doRun
- SystemClock::Endless and others unconditionally wrote to stdout.
  This is undesirable when simulavr is used as a library.
  The output was moved to cmd/main.c. This way, the simulavr binary gives the
  same diagnostic messages, but the library itself is silent

Also, Step, Run, adn RunTimeRange return the number of steps to improve
usability of these methods from a library.
---
 src/avrdevice.cpp     |    2 +-
 src/cmd/gdbserver.cpp |    2 +-
 src/cmd/main.cpp      |   21 ++++++++++++++++----
 src/systemclock.cpp   |   51 +++++++++++++++++++++++++------------------------
 src/systemclock.h     |   13 +++++++------
 5 files changed, 52 insertions(+), 37 deletions(-)

diff --git a/src/avrdevice.cpp b/src/avrdevice.cpp
index 3ec0b48..9d1e768 100644
--- a/src/avrdevice.cpp
+++ b/src/avrdevice.cpp
@@ -471,7 +471,7 @@ int AvrDevice::Step(bool &untilCoreStepFinished, SystemClockOffset *nextStepIn_n
             if(EP.end() != find(EP.begin(), EP.end(), PC)) {
                 if(global_verbose_on)
                     cout << "Simulation finished!" << endl;
-                SystemClock::Instance().stop();
+                SystemClock::Instance().Stop();
                 dumpManager->cycle();
                 return 0;
             }
diff --git a/src/cmd/gdbserver.cpp b/src/cmd/gdbserver.cpp
index 936f39d..0527cb5 100644
--- a/src/cmd/gdbserver.cpp
+++ b/src/cmd/gdbserver.cpp
@@ -1513,7 +1513,7 @@ int GdbServer::InternalStep(bool &untilCoreStepFinished, SystemClockOffset *time
                 leave = false;
             }
 
-            if(!leave) { //we can�t leave the loop so we have to request the other gdb instances now!
+            if(!leave) { //we can't leave the loop so we have to request the other gdb instances now!
                 // step through all gdblist members WITHOUT my self!
                 //cout << "we do not leave and check for gdb events" << endl;
                 vector<GdbServer*>::iterator ii;
diff --git a/src/cmd/main.cpp b/src/cmd/main.cpp
index 68ac132..873d7d5 100644
--- a/src/cmd/main.cpp
+++ b/src/cmd/main.cpp
@@ -404,19 +404,32 @@ int main(int argc, char *argv[]) {
     
     dman->start(); // start dump session
     
+    long steps = 0;
     if(gdbserver_flag == 0) { // no gdb
         SystemClock::Instance().Add(dev1);
         if(maxRunTime == 0) {
-            SystemClock::Instance().Endless();
+            steps = SystemClock::Instance().Endless();
+            cout << "SystemClock::Endless stopped" << endl
+                 << "number of cpu cycles simulated: " << dec << steps << endl;
         } else {                                           // limited
-            SystemClock::Instance().Run(maxRunTime);
+            steps = SystemClock::Instance().Run(maxRunTime);
+            cout << "Ran too long.  Terminated after " << maxRunTime
+                 << " ns (simulated) and " << endl 
+                 << steps << " cpu cycles" << endl;
         }
+		Application::GetInstance()->PrintResults();
+
     } else { // gdb should be activated
         if(global_verbose_on)
-            cout << "Going to gdb..." << endl;
+            cout << "Waiting for gdb..." << endl;
         GdbServer gdb1(dev1, global_gdbserver_port, global_gdb_debug, globalWaitForGdbConnection);
         SystemClock::Instance().Add(&gdb1);
-        SystemClock::Instance().Endless();
+        steps = SystemClock::Instance().Endless();
+        if(global_verbose_on) {
+			cout << "SystemClock::Endless stopped" << endl;
+			cout << "number of cpu cycles simulated: " << dec << steps << endl;
+			Application::GetInstance()->PrintResults();
+		}
     }
     
     dman->stopApplication(); // stop dump session. Close dump files, if necessary
diff --git a/src/systemclock.cpp b/src/systemclock.cpp
index 879706b..ca4223a 100644
--- a/src/systemclock.cpp
+++ b/src/systemclock.cpp
@@ -35,6 +35,7 @@
 
 using namespace std;
 
+static volatile bool breakMessage = false;
 
 template<typename Key, typename Value>
 MinHeap<Key, Value>::MinHeap()
@@ -140,7 +141,8 @@ void SystemClock::AddAsyncMember(SimulationMember *dev) {
 }
 
 int SystemClock::Step(bool &untilCoreStepFinished) {
-    //0-> return also if cpu in waitstate 1-> return if cpu is really finished
+    //0-> return also if cpu in waitstate 
+	//1-> return if cpu is really finished
     int res = 0; // returns the state from a core step. Needed by gdb-server to
                  // watch for breakpoints
 
@@ -154,8 +156,10 @@ int SystemClock::Step(bool &untilCoreStepFinished) {
         SystemClockOffset nextStepIn_ns = -1;
         
         // do a step on simulation member
-        res = core->Step(untilCoreStepFinished, &nextStepIn_ns);
-        
+        int rc = core->Step(untilCoreStepFinished, &nextStepIn_ns);
+        if (rc)
+            res = rc;
+
         if(nextStepIn_ns == 0) { // insert the next step behind the following!
             nextStepIn_ns = 1 + (syncMembers.IsEmpty() ? currentTime : syncMembers.front().first);
         } else if(nextStepIn_ns > 0)
@@ -176,6 +180,10 @@ int SystemClock::Step(bool &untilCoreStepFinished) {
         }
     }
 
+    // honour the stop command
+    if (breakMessage)
+        return 1;
+
     return res;
 }
 
@@ -192,15 +200,13 @@ void SystemClock::Reschedule(SimulationMember *sm, SystemClockOffset newTime) {
     syncMembers.Insert(newTime+currentTime+1, sm);
 }
 
-static volatile int breakMessage = false;
-
 void OnBreak(int s) {
     signal(SIGINT, SIG_DFL);
     signal(SIGTERM, SIG_DFL);
     breakMessage = true;
 }
 
-void SystemClock::stop() {
+void SystemClock::Stop() {
     breakMessage = true;
 }
 
@@ -211,8 +217,8 @@ void SystemClock::ResetClock(void) {
     currentTime = 0;
 }
 
-void SystemClock::Endless() {
-    int steps = 0;
+long SystemClock::Endless() {
+    long steps = 0;
     
     signal(SIGINT, OnBreak);
     signal(SIGTERM, OnBreak);
@@ -223,14 +229,11 @@ void SystemClock::Endless() {
         Step(untilCoreStepFinished);
     }
 
-    cout << "SystemClock::Endless stopped" << endl;
-    cout << "number of cpu cycles simulated: " << dec << steps << endl;
-    Application::GetInstance()->PrintResults();
+    return steps;
 }
 
-
-void SystemClock::Run(SystemClockOffset maxRunTime) {
-    int steps = 0;
+long SystemClock::Run(SystemClockOffset maxRunTime) {
+    long steps = 0;
     
     signal(SIGINT, OnBreak);
     signal(SIGTERM, OnBreak);
@@ -238,18 +241,16 @@ void SystemClock::Run(SystemClockOffset maxRunTime) {
     while((breakMessage== false) &&
           (SystemClock::Instance().GetCurrentTime() < maxRunTime)) {
         steps++;
-        bool untilCoreStepFinished =false;
-        Step(untilCoreStepFinished);
+        bool untilCoreStepFinished = false;
+        if (Step(untilCoreStepFinished))
+            break;
     }
 
-    cout << endl << "Ran too long.  Terminated after " << maxRunTime;
-    cout << " simulated nanoseconds." << endl;
-
-    Application::GetInstance()->PrintResults();
+    return steps;
 }
 
-int SystemClock::RunTimeRange(SystemClockOffset timeRange) {
-    int res = 0;
+long SystemClock::RunTimeRange(SystemClockOffset timeRange) {
+	long steps = 0;
     bool untilCoreStepFinished;
     
     signal(SIGINT, OnBreak);
@@ -258,12 +259,12 @@ int SystemClock::RunTimeRange(SystemClockOffset timeRange) {
     timeRange += SystemClock::Instance().GetCurrentTime();
     while((breakMessage == false) && (SystemClock::Instance().GetCurrentTime() < timeRange)) {
         untilCoreStepFinished = false;
-        res = Step(untilCoreStepFinished);
-        if(res != 0)
+        if (Step(untilCoreStepFinished))
             break;
+        steps++;
     }
     
-    return res;
+    return steps;
 }
 
 SystemClock& SystemClock::Instance() {
diff --git a/src/systemclock.h b/src/systemclock.h
index 85d2364..a2d6be6 100644
--- a/src/systemclock.h
+++ b/src/systemclock.h
@@ -90,12 +90,13 @@ class SystemClock
         void AddAsyncMember(SimulationMember *dev);
         //! Process one simulation step
         int Step(bool &untilCoreStepFinished);
-        //! Run simulation endless till SIGINT or SIGTERM signal
-        void Endless();
+        /*! Run simulation endless till SIGINT or SIGTERM signal
+			\return the number of CPU cycles */
+        long Endless();
         //! Run simulation till given time is arrived or signal is cached
-        void Run(SystemClockOffset maxRunTime);
+        long Run(SystemClockOffset maxRunTime);
         //! Like Run method, but stops on breakpoint or after given time offset
-        int RunTimeRange(SystemClockOffset timeRange);
+        long RunTimeRange(SystemClockOffset timeRange);
         //! Returns the central SystemClock instance for the application
         /*! There will be only one instance on a application! */
         static SystemClock& Instance();
@@ -107,8 +108,8 @@ class SystemClock
         void Reschedule(SimulationMember *sm, SystemClockOffset newTime);
         //! Switches trace mode for all current found simulation members
         void SetTraceModeForAllMembers(int trace_on);
-        //! Gives the possibillity to stop Run od Endless method by programm
-        void stop();
+        //! Stop Run/Endless or Step asynchronously
+        void Stop();
         //! Resets the simulation time and clears table for simulation members and async simulation members
         void ResetClock(void);
 };
-- 
1.7.9.4

