From 8fdd6ee6fb6f5297cea4f7271becd2af7d0828ab Mon Sep 17 00:00:00 2001
From: Lars Immisch <lars@ibp.de>
Date: Sat, 21 Apr 2012 01:11:25 +0200
Subject: [PATCH] Allow different simulation runs per process.

With this change, it is possible to run multiple simulations with different
binaries or devices in the same process.

This is useful for unit-test scenarios, e.g. from python.
---
 src/avrdevice.cpp               |   16 +++++++++-------
 src/avrdevice.h                 |    6 +++++-
 src/cmd/main.cpp                |    2 +-
 src/python/pysimulationmember.h |    3 +++
 src/systemclock.cpp             |    5 +++--
 src/systemclock.h               |    2 +-
 src/traceval.cpp                |   37 ++++++++++++++++++++++++++++---------
 src/traceval.h                  |   15 +++++++++++----
 src/ui/ui.cpp                   |    2 +-
 9 files changed, 62 insertions(+), 26 deletions(-)

diff --git a/src/avrdevice.cpp b/src/avrdevice.cpp
index e2230db..3ec0b48 100644
--- a/src/avrdevice.cpp
+++ b/src/avrdevice.cpp
@@ -278,8 +278,10 @@ Pin *AvrDevice::GetPin(const char *name) {
 }
 
 AvrDevice::~AvrDevice() {
-    // unregister device on DumpManager
-    dump_manager->unregisterAvrDevice(this);
+    if (dumpManager) {
+        // unregister device on DumpManager
+        dumpManager->unregisterAvrDevice(this);
+    }
     
     // delete invalid RW memory cells on shadow store + shadow store self
     unsigned size = totalIoSpace - registerSpaceSize - iRamSize - eRamSize;
@@ -342,8 +344,8 @@ AvrDevice::AvrDevice(unsigned int _ioSpaceSize,
     flagXMega(false),
     instructionSEIJustEnabledInterrupts(false)
 {
-    dump_manager = DumpManager::Instance();
-    dump_manager->registerAvrDevice(this);
+    dumpManager = DumpManager::Instance();
+    dumpManager->registerAvrDevice(this);
 	DebugRecentJumpsIndex = 0;
     
     TraceValue* pc_tracer=trace_direct(&coreTraceGroup, "PC", &cPC);
@@ -462,7 +464,7 @@ int AvrDevice::Step(bool &untilCoreStepFinished, SystemClockOffset *nextStepIn_n
                 if(nextStepIn_ns != 0)
                     *nextStepIn_ns=clockFreq;
                 untilCoreStepFinished = !(cpuCycles > 0);
-                dump_manager->cycle();
+                dumpManager->cycle();
                 return BREAK_POINT;
             }
 
@@ -470,7 +472,7 @@ int AvrDevice::Step(bool &untilCoreStepFinished, SystemClockOffset *nextStepIn_n
                 if(global_verbose_on)
                     cout << "Simulation finished!" << endl;
                 SystemClock::Instance().stop();
-                dump_manager->cycle();
+                dumpManager->cycle();
                 return 0;
             }
 
@@ -531,7 +533,7 @@ int AvrDevice::Step(bool &untilCoreStepFinished, SystemClockOffset *nextStepIn_n
     }
 
     untilCoreStepFinished = !((cpuCycles > 0) || hwWait);
-    dump_manager->cycle();
+    dumpManager->cycle();
     return (cpuCycles < 0) ? cpuCycles : 0;
 }
 
diff --git a/src/avrdevice.h b/src/avrdevice.h
index 9141e17..d5311ad 100644
--- a/src/avrdevice.h
+++ b/src/avrdevice.h
@@ -62,6 +62,10 @@ class AvrDevice: public SimulationMember, public TraceValueRegister {
         static const unsigned int registerSpaceSize;
         const unsigned int iRamSize;
         const unsigned int eRamSize;
+
+        void detachDumpManager() { dumpManager = NULL; }
+
+        friend class DumpManager;
         
     protected:
         SystemClockOffset clockFreq;  ///< Period of a tick (1/F_OSC) in [ns]
@@ -114,7 +118,7 @@ class AvrDevice: public SimulationMember, public TraceValueRegister {
         std::vector<Hardware *> hwResetList; 
         std::vector<Hardware *> hwCycleList; 
 
-        DumpManager *dump_manager;
+        DumpManager *dumpManager;
     
         AvrDevice(unsigned int ioSpaceSize, unsigned int IRamSize, unsigned int ERamSize, unsigned int flashSize);
         virtual ~AvrDevice();
diff --git a/src/cmd/main.cpp b/src/cmd/main.cpp
index 51e8de3..68ac132 100644
--- a/src/cmd/main.cpp
+++ b/src/cmd/main.cpp
@@ -328,7 +328,7 @@ int main(int argc, char *argv[]) {
         }
     }
     
-    /* get dump manager an inform it, that we have a single device application */
+    /* get dump manager and inform it that we have a single device application */
     DumpManager *dman = DumpManager::Instance();
     dman->SetSingleDeviceApp();
     
diff --git a/src/python/pysimulationmember.h b/src/python/pysimulationmember.h
index 88134a9..6bd26a6 100644
--- a/src/python/pysimulationmember.h
+++ b/src/python/pysimulationmember.h
@@ -37,6 +37,9 @@
   this value will be used in call of method Step. Method Step here returns allways 0.*/
 class PySimulationMember: public SimulationMember {
     public:
+
+        virtual ~PySimulationMember() {}
+
         //! Process a time step, timeToNextStepIn_ns represents time to next call in ns.
         virtual int Step(bool &trueHwStep, SystemClockOffset *timeToNextStepIn_ns) {
             SystemClockOffset t = DoStep(trueHwStep);
diff --git a/src/systemclock.cpp b/src/systemclock.cpp
index 787c90e..879706b 100644
--- a/src/systemclock.cpp
+++ b/src/systemclock.cpp
@@ -179,7 +179,7 @@ int SystemClock::Step(bool &untilCoreStepFinished) {
     return res;
 }
 
-void SystemClock::Rescedule(SimulationMember *sm, SystemClockOffset newTime) {
+void SystemClock::Reschedule(SimulationMember *sm, SystemClockOffset newTime) {
     MinHeap<SystemClockOffset, SimulationMember *>::iterator ii;
 
     for(ii=syncMembers.begin(); ii != syncMembers.end(); ii++) {
@@ -192,7 +192,7 @@ void SystemClock::Rescedule(SimulationMember *sm, SystemClockOffset newTime) {
     syncMembers.Insert(newTime+currentTime+1, sm);
 }
 
-volatile int breakMessage = false;
+static volatile int breakMessage = false;
 
 void OnBreak(int s) {
     signal(SIGINT, SIG_DFL);
@@ -205,6 +205,7 @@ void SystemClock::stop() {
 }
 
 void SystemClock::ResetClock(void) {
+    breakMessage = false;
     asyncMembers.clear();
     syncMembers.clear();
     currentTime = 0;
diff --git a/src/systemclock.h b/src/systemclock.h
index 54b7171..85d2364 100644
--- a/src/systemclock.h
+++ b/src/systemclock.h
@@ -104,7 +104,7 @@ class SystemClock
             given offset to current simulation time + 1.
             
             \todo This method is possibly obsolete! */
-        void Rescedule(SimulationMember *sm, SystemClockOffset newTime);
+        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
diff --git a/src/traceval.cpp b/src/traceval.cpp
index c0a8bb7..c64749d 100644
--- a/src/traceval.cpp
+++ b/src/traceval.cpp
@@ -520,11 +520,23 @@ bool DumpVCD::enabled(const TraceValue *t) const {
 
 DumpVCD::~DumpVCD() { delete os; }
 
+
+int DumpManager::_devidx = 0;
+DumpManager *::DumpManager::_instance;
+
 DumpManager* DumpManager::Instance(void) {
-    static DumpManager *f;
-    if(f == NULL)
-        f = new DumpManager();
-    return f;
+    if(_instance == NULL)
+        _instance = new DumpManager();
+    return _instance;
+}
+
+void DumpManager::Reset(void) {
+	if (_instance) {
+		_instance->detachAvrDevices();
+		delete _instance;
+	}
+	_instance = NULL;
+	_devidx = 0;
 }
 
 DumpManager::DumpManager() {
@@ -532,12 +544,11 @@ DumpManager::DumpManager() {
 }
 
 void DumpManager::appendDeviceName(std::string &s) {
-    static int devidx = 0;
-    devidx++;
-    if(singleDeviceApp && devidx > 1)
+    _devidx++;
+    if(singleDeviceApp && _devidx > 1)
         avr_error("Can't create device name twice, because it's a single device application");
     if(!singleDeviceApp)
-        s += "Dev" + int2str(devidx);
+        s += "Dev" + int2str(_devidx);
 }
 
 void DumpManager::registerAvrDevice(AvrDevice* dev) {
@@ -554,6 +565,14 @@ void DumpManager::unregisterAvrDevice(AvrDevice* dev) {
     devices.swap(dl);
 }
 
+void DumpManager::detachAvrDevices() {
+    vector<AvrDevice*> dl;
+    for(vector<AvrDevice*>::iterator i = devices.begin(); i != devices.end(); i++) {
+        AvrDevice* d = *i;
+		d->detachDumpManager();
+    }
+}
+
 TraceValue* DumpManager::seekValueByName(const std::string &name) {
     if(singleDeviceApp) {
         if(devices.size() == 0)
@@ -574,7 +593,7 @@ TraceValue* DumpManager::seekValueByName(const std::string &name) {
 
 void DumpManager::SetSingleDeviceApp(void) {
     if(devices.size() > 0)
-        avr_error("method SetSingleDeviceApp have to be used before creating and adding devices to DumpManager");
+        avr_error("method SetSingleDeviceApp must be called before devices are added");
     singleDeviceApp = true;
 }
 
diff --git a/src/traceval.h b/src/traceval.h
index 5f02f94..7ae1869 100644
--- a/src/traceval.h
+++ b/src/traceval.h
@@ -331,7 +331,8 @@ class DumpManager {
     public:
         //! Singleton class access.
         static DumpManager* Instance(void);
-        
+		static void Reset();
+         
         //! Tell DumpManager, that we have only one device
         /*! In normal simulavr application we have only one device aka processor.
          But it's possible to make a simulation with 2 or more devices together.
@@ -352,7 +353,7 @@ class DumpManager {
     
         //! Stop processing on all dumpers and removes it from dumpers list
         void stopApplication(void);
-        
+
         /*! Process one AVR clock cycle. Must be done after the AVR did all
           processing so that changed values etc. can be collected. */
         void cycle();
@@ -388,13 +389,16 @@ class DumpManager {
         
         //! append a unique device name to a string
         void appendDeviceName(std::string &s);
-        
+
         //! Add a device to devicelist
         void registerAvrDevice(AvrDevice* dev);
         
         //! Remove a device from devicelist
         void unregisterAvrDevice(AvrDevice* dev);
         
+        //! detach all devices
+        void detachAvrDevices();
+
         //! Seek value by name in all devices
         TraceValue* seekValueByName(const std::string &name);
         
@@ -411,6 +415,9 @@ class DumpManager {
         
         //! Device list
         std::vector<AvrDevice*> devices;
+
+        static int _devidx;
+        static DumpManager *_instance;
 };
 
 //! Build a register for TraceValue's
@@ -487,7 +494,7 @@ class TraceValueCoreRegister: public TraceValueRegister {
 
         //! helper function to split up into name an number tail
         int _tvr_numberindex(const std::string &str);
-        
+
     protected:
         //! Get the count of all TraceValues, that are registered here and descending
         /*! This includes here also values in _tvr_valset! */
diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp
index fe0e433..0d7e211 100644
--- a/src/ui/ui.cpp
+++ b/src/ui/ui.cpp
@@ -138,7 +138,7 @@ void UserInterface::SendUiNewState(const string &s, const char &c)  {
     os << "set " << s << " " << c << endl;
     Write(os.str());
 
-    //    SystemClock::Instance().Rescedule(this, 1000); //read ack back as fast as possible
+    //    SystemClock::Instance().Reschedule(this, 1000); //read ack back as fast as possible
 }
 
 void UserInterface::SetNewValueFromUi(const string &value){
-- 
1.7.9.4

