File indexing completed on 2025-02-16 08:27:30
0001 /*************************************************************************** 0002 * Copyright (C) 2005 by David Saxton * 0003 * david@bluehaze.org * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 ***************************************************************************/ 0010 0011 #ifndef SIMULATOR_H 0012 #define SIMULATOR_H 0013 0014 #include <list> 0015 0016 #include "circuit.h" 0017 #include "logic.h" 0018 0019 /** 0020 This should be a multiple of 1000. It is the number of times a second that 0021 linear elements are updated. 0022 */ 0023 const int LINEAR_UPDATE_RATE = int(10000); 0024 const double LINEAR_UPDATE_PERIOD = 1.0 / LINEAR_UPDATE_RATE; 0025 0026 const int SIMULATOR_STEP_INTERVAL_MS = 20; 0027 0028 /** 0029 This should be a multiple of 1000. It is the number of times a second that 0030 logic elements are updated. 0031 */ 0032 const int LOGIC_UPDATE_RATE = int(1000000); 0033 0034 const int LOGIC_UPDATE_PER_STEP = int(LOGIC_UPDATE_RATE / LINEAR_UPDATE_RATE); 0035 0036 class QTimer; 0037 0038 class Circuit; 0039 0040 class CircuitDocument; 0041 0042 class Component; 0043 0044 class ComponentCallback; 0045 0046 class ECNode; 0047 0048 class GpsimProcessor; 0049 0050 class LogicIn; 0051 0052 class LogicOut; 0053 0054 class Switch; 0055 0056 class Wire; 0057 0058 typedef QList<ECNode *> ECNodeList; 0059 typedef QList<LogicIn *> LogicInList; 0060 typedef void (Component::*VoidCallbackPtr)(); 0061 0062 class ComponentCallback 0063 { 0064 public: 0065 ComponentCallback(Component *component, VoidCallbackPtr function) 0066 { 0067 m_pComponent = component; 0068 m_pFunction = function; 0069 } 0070 0071 void callback() 0072 { 0073 (m_pComponent->*m_pFunction)(); 0074 } 0075 0076 Component *component() const 0077 { 0078 return m_pComponent; 0079 } 0080 0081 protected: 0082 Component *m_pComponent; 0083 VoidCallbackPtr m_pFunction; 0084 }; 0085 0086 /** 0087 This singleton class oversees all simulation (keeping in sync linear, nonlinear, 0088 logic, external simulators (such as gpsim), mechanical simulation, etc). 0089 @author David Saxton 0090 */ 0091 0092 class Simulator : public QObject 0093 { 0094 Q_OBJECT 0095 0096 public: 0097 static bool isDestroyedSim(); 0098 static Simulator *self(); 0099 ~Simulator() override; 0100 0101 /** 0102 * Number of (1/LOGIC_UPDATE_RATE) intervals that the simulator has been 0103 * stepping for. 0104 */ 0105 long long time() const; /* { 0106 return m_stepNumber * LOGIC_UPDATE_PER_STEP + m_llNumber; 0107 } */ 0108 0109 /** 0110 * Initializes a new logic chain. 0111 */ 0112 void createLogicChain(LogicOut *logicOut, const LogicInList &logicInList, const PinList &pinList); 0113 /** 0114 * Adds the given LogicOut to the list of changed LogicOuts 0115 */ 0116 void addChangedLogic(LogicOut *changed) 0117 { 0118 m_pChangedLogicLast->setNextChanged(changed, m_currentChain); 0119 m_pChangedLogicLast = changed; 0120 } 0121 0122 /** 0123 * Remove pointers to the given LogicOut, called when it is deleted for 0124 * safety reasons. 0125 */ 0126 void removeLogicOutReferences(LogicOut *logic); 0127 /** 0128 * Remove pointers to the given LogicIn, called when it is deleted for 0129 * safety reasons. Simulator does not have any references to LogicIns 0130 * itself - instead, they are removed from logic chains which are 0131 * currently marked as changed. 0132 */ 0133 void removeLogicInReferences(LogicIn *logic); 0134 /** 0135 * Adds the given Circuit to the list of changed Circuits 0136 */ 0137 void addChangedCircuit(Circuit *changed) 0138 { 0139 m_pChangedCircuitLast->setNextChanged(changed, m_currentChain); 0140 m_pChangedCircuitLast = changed; 0141 } 0142 0143 /** 0144 * add a callback to be executed at the current step, at the given logic update number 0145 * @param at the logic update number 0146 * @param ccb the callback that shold be called; note that the ownership of the callback 0147 * object remains at the caller 0148 */ 0149 inline void addStepCallback(int at, ComponentCallback *ccb); 0150 /** 0151 * Add the given processor to the simulator. GpsimProcessor::step will 0152 * be called while present in the simulator (it is at GpsimProcessor's 0153 * disgression whether to actually step, depending on its running 0154 * status). 0155 * @see detachGpsimProcessor( GpsimProcessor * cpu ); 0156 */ 0157 void attachGpsimProcessor(GpsimProcessor *cpu); 0158 /** 0159 * Remove the given processor from the simulation loop 0160 */ 0161 void detachGpsimProcessor(GpsimProcessor *cpu); 0162 /** 0163 * Attach the component callback to the simulator. This will be called 0164 * during the logic update loop, at LOGIC_UPDATE_RATE times per second (so 0165 * make sure the function passed is an efficient one!). 0166 */ 0167 void attachComponentCallback(Component *component, VoidCallbackPtr function); 0168 /** 0169 * Removes the callbacks for the given component from the simulator. 0170 */ 0171 void detachComponentCallbacks(Component &component); 0172 /** 0173 * Attach the component to the simulator. 0174 */ 0175 void attachComponent(Component *component); 0176 /** 0177 * Detaches the component from the simulator. 0178 */ 0179 void detachComponent(Component *component); 0180 /** 0181 * Attach a circuit to the simulator 0182 */ 0183 void attachCircuit(Circuit *circuit); 0184 /** 0185 * Detach a circuit from the simulator. 0186 */ 0187 void detachCircuit(Circuit *circuit); 0188 0189 /** 0190 * @return whether or not we are currently simulating stuff 0191 * @see slotSetSimulating 0192 */ 0193 bool isSimulating() const 0194 { 0195 return m_bIsSimulating; 0196 } 0197 0198 signals: 0199 /** 0200 * Emitted when the simulating state changes. 0201 * @see slotSetSimulating 0202 */ 0203 void simulatingStateChanged(bool isSimulating); 0204 0205 public slots: 0206 /** 0207 * Set whether or not to simulate at the moment. 0208 * @see isSimulating 0209 */ 0210 void slotSetSimulating(bool simulate); 0211 0212 private slots: 0213 void step(); 0214 void printTimingStatistics(); 0215 0216 private: 0217 bool m_bIsSimulating; 0218 // static Simulator *m_pSelf; 0219 0220 QTimer *m_stepTimer; 0221 0222 /// List of LogicOuts that are at the start of a LogicChain 0223 QList<LogicOut *> m_logicChainStarts; 0224 std::list<GpsimProcessor *> *m_gpsimProcessors; 0225 0226 // doesn't look too appropriate. 0227 // essentially a grab bag of every odd *component* that answers "true" to does step non-logic, 0228 // Which is every component that has special UI-related code that needs to be called every time the simulator steps. 0229 // this is not to be confused with elements which have nonLinear and Reactive components. =P 0230 std::list<Component *> *m_components; 0231 std::list<ComponentCallback> *m_componentCallbacks; 0232 std::list<Circuit *> *m_ordinaryCircuits; 0233 0234 // allow a variable number of callbacks be scheduled at each possible time. 0235 std::list<ComponentCallback *> *m_pStartStepCallback[LOGIC_UPDATE_PER_STEP]; 0236 0237 Circuit *m_pChangedCircuitStart; 0238 Circuit *m_pChangedCircuitLast; 0239 0240 LogicOut *m_pChangedLogicStart; 0241 LogicOut *m_pChangedLogicLast; 0242 0243 QTimer *m_printTimingStatsTimer; 0244 qint64 m_stepMaxNs; 0245 double m_stepRollingAvgNs; 0246 qint64 m_stepLastNs; 0247 qint64 m_stepsSinceStart; 0248 qint64 m_stepsSincePrint; 0249 0250 public: 0251 Simulator(); 0252 0253 private: 0254 unsigned long m_llNumber; // simulation clock; Exists only to support the time() callback. 0255 long long m_stepNumber; 0256 0257 // looks like there are only ever two chains, 0 and 1, code elsewhere toggles between the two... 0258 unsigned char m_currentChain; 0259 }; 0260 0261 inline void Simulator::addStepCallback(int at, ComponentCallback *ccb) 0262 { 0263 // code was buggy[er], don't really know what variables are for, rewritten to make it work, 0264 // OK for now. 0265 if ((at < 0) || (at >= LOGIC_UPDATE_PER_STEP)) { 0266 return; // note: maybe log here the error 0267 } 0268 if (!m_pStartStepCallback[at]) { 0269 m_pStartStepCallback[at] = new std::list<ComponentCallback *>; 0270 } 0271 0272 m_pStartStepCallback[at]->push_back(ccb); 0273 } 0274 0275 #endif