File indexing completed on 2024-12-08 11:07:18
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 #include "simulator.h" 0012 #include "component.h" 0013 #include "gpsimprocessor.h" 0014 #include "pin.h" 0015 #include "switch.h" 0016 0017 #include "ktechlab_debug.h" 0018 0019 // #include <k3staticdeleter.h> 0020 0021 #include <QDebug> 0022 #include <QElapsedTimer> 0023 #include <QGlobalStatic> 0024 #include <QSet> 0025 #include <QTimer> 0026 0027 #include <cassert> 0028 0029 using namespace std; 0030 0031 // BEGIN class Simulator 0032 // Simulator *Simulator::m_pSelf = 0; 0033 // static K3StaticDeleter<Simulator> staticSimulatorDeleter; 0034 0035 Q_GLOBAL_STATIC(Simulator, globalSimulator); 0036 0037 bool Simulator::isDestroyedSim() 0038 { 0039 return globalSimulator.isDestroyed(); 0040 } 0041 0042 Simulator *Simulator::self() 0043 { 0044 // if (!m_pSelf) 0045 // staticSimulatorDeleter.setObject(m_pSelf, new Simulator()); 0046 // 0047 // return m_pSelf; 0048 return globalSimulator; 0049 } 0050 0051 Simulator::Simulator() 0052 : m_bIsSimulating(false) 0053 , m_printTimingStatsTimer(nullptr) 0054 , m_stepMaxNs(0) 0055 , m_stepRollingAvgNs(0) 0056 , m_stepLastNs(0) 0057 , m_stepsSinceStart(0) 0058 , m_stepsSincePrint(0) 0059 , m_llNumber(0) 0060 , m_stepNumber(0) 0061 , m_currentChain(0) 0062 { 0063 m_gpsimProcessors = new list<GpsimProcessor *>; 0064 m_componentCallbacks = new list<ComponentCallback>; 0065 m_components = new list<Component *>; 0066 m_ordinaryCircuits = new list<Circuit *>; 0067 0068 // use integer math for these, update period is double. 0069 unsigned max = unsigned(LOGIC_UPDATE_RATE / LINEAR_UPDATE_RATE); 0070 0071 for (unsigned i = 0; i < max; i++) { 0072 m_pStartStepCallback[i] = nullptr; 0073 } 0074 0075 LogicConfig lc; 0076 0077 m_pChangedLogicStart = new LogicOut(lc, false); 0078 m_pChangedLogicLast = m_pChangedLogicStart; 0079 0080 m_pChangedCircuitStart = new Circuit; 0081 m_pChangedCircuitLast = m_pChangedCircuitStart; 0082 0083 m_stepTimer = new QTimer(this); 0084 connect(m_stepTimer, &QTimer::timeout, this, &Simulator::step); 0085 0086 m_printTimingStatsTimer = new QTimer(this); 0087 connect(m_printTimingStatsTimer, &QTimer::timeout, this, &Simulator::printTimingStatistics); 0088 if (0) { // note: enable this when you want to debug the performance of the simulator; maybe turn it to run-time options 0089 m_printTimingStatsTimer->start(1000); 0090 } 0091 0092 slotSetSimulating(true); // start the timer 0093 } 0094 0095 Simulator::~Simulator() 0096 { 0097 delete m_pChangedLogicStart; 0098 delete m_pChangedCircuitStart; 0099 0100 delete m_gpsimProcessors; 0101 delete m_components; 0102 delete m_componentCallbacks; 0103 delete m_ordinaryCircuits; 0104 } 0105 0106 long long Simulator::time() const 0107 { 0108 return m_stepNumber * LOGIC_UPDATE_PER_STEP + m_llNumber; 0109 } 0110 0111 void Simulator::step() 0112 { 0113 if (!m_bIsSimulating) 0114 return; 0115 0116 QElapsedTimer execTimer; 0117 execTimer.start(); 0118 0119 // We are called a thousand times a second (the maximum allowed by QTimer), 0120 // so divide the LINEAR_UPDATE_RATE by 1e3 for the number of loops we need 0121 // to do. 0122 const unsigned maxSteps = unsigned(LINEAR_UPDATE_RATE / SIMULATOR_STEP_INTERVAL_MS); 0123 0124 for (unsigned i = 0; i < maxSteps; ++i) { 0125 // here starts 1 linear step 0126 m_stepNumber++; 0127 0128 // Update the non-logic parts of the simulation 0129 { 0130 list<Component *>::iterator components_end = m_components->end(); 0131 0132 for (list<Component *>::iterator component = m_components->begin(); component != components_end; component++) { 0133 (*component)->stepNonLogic(); 0134 } 0135 } 0136 0137 { 0138 list<Circuit *>::iterator circuits_end = m_ordinaryCircuits->end(); 0139 0140 for (list<Circuit *>::iterator circuit = m_ordinaryCircuits->begin(); circuit != circuits_end; circuit++) { 0141 (*circuit)->doNonLogic(); 0142 } 0143 } 0144 0145 // Update the logic parts of our simulation 0146 // const unsigned max = unsigned(LOGIC_UPDATE_RATE / LINEAR_UPDATE_RATE); // 2015.09.27 - use contants for logic updates 0147 0148 for (m_llNumber = 0; m_llNumber < LOGIC_UPDATE_PER_STEP; ++m_llNumber) { 0149 // here starts 1 logic update 0150 // Update the logic components 0151 { 0152 list<ComponentCallback>::iterator callbacks_end = m_componentCallbacks->end(); 0153 0154 for (list<ComponentCallback>::iterator callback = m_componentCallbacks->begin(); callback != callbacks_end; callback++) { 0155 callback->callback(); 0156 } 0157 } 0158 0159 if (m_pStartStepCallback[m_llNumber]) { 0160 list<ComponentCallback *>::iterator callbacks_end = m_pStartStepCallback[m_llNumber]->end(); 0161 0162 for (list<ComponentCallback *>::iterator callback = m_pStartStepCallback[m_llNumber]->begin(); callback != callbacks_end; callback++) { 0163 (*callback)->callback(); 0164 // should we delete the list entry? no 0165 } 0166 } 0167 0168 delete m_pStartStepCallback[m_llNumber]; 0169 m_pStartStepCallback[m_llNumber] = nullptr; 0170 0171 #ifndef NO_GPSIM 0172 // Update the gpsim processors 0173 { 0174 list<GpsimProcessor *>::iterator processors_end = m_gpsimProcessors->end(); 0175 0176 for (list<GpsimProcessor *>::iterator processor = m_gpsimProcessors->begin(); processor != processors_end; processor++) { 0177 (*processor)->executeNext(); 0178 } 0179 } 0180 #endif 0181 0182 // why do we change this here instead of later? 0183 int prevChain = m_currentChain; 0184 m_currentChain ^= 1; 0185 0186 // Update the non-logic circuits 0187 if (Circuit *changed = m_pChangedCircuitStart->nextChanged(prevChain)) { 0188 QSet<Circuit *> canAddChangedSet; 0189 for (Circuit *circuit = changed; circuit && (!canAddChangedSet.contains(circuit)); circuit = circuit->nextChanged(prevChain)) { 0190 circuit->setCanAddChanged(true); 0191 canAddChangedSet.insert(circuit); 0192 } 0193 0194 m_pChangedCircuitStart->setNextChanged(nullptr, prevChain); 0195 m_pChangedCircuitLast = m_pChangedCircuitStart; 0196 0197 do { 0198 Circuit *next = changed->nextChanged(prevChain); 0199 changed->setNextChanged(nullptr, prevChain); 0200 changed->doLogic(); 0201 changed = next; 0202 } while (changed); 0203 } 0204 0205 // Call the logic callbacks 0206 if (LogicOut *changed = m_pChangedLogicStart->nextChanged(prevChain)) { 0207 for (LogicOut *out = changed; out; out = out->nextChanged(prevChain)) 0208 out->setCanAddChanged(true); 0209 0210 m_pChangedLogicStart->setNextChanged(nullptr, prevChain); 0211 m_pChangedLogicLast = m_pChangedLogicStart; 0212 0213 do { 0214 LogicOut *next = changed->nextChanged(prevChain); 0215 changed->setNextChanged(nullptr, prevChain); 0216 0217 double v = changed->isHigh() ? changed->outputHighVoltage() : 0.0; 0218 0219 for (PinList::iterator it = changed->pinListBegin; it != changed->pinListEnd; ++it) { 0220 if (Pin *pin = *it) 0221 pin->setVoltage(v); 0222 } 0223 0224 LogicIn *logicCallback = changed; 0225 0226 while (logicCallback) { 0227 logicCallback->callCallback(); 0228 logicCallback = logicCallback->nextLogic(); 0229 } 0230 0231 changed = next; 0232 } while (changed); 0233 } 0234 } 0235 } 0236 0237 { 0238 const qint64 elapsedNs = execTimer.nsecsElapsed(); 0239 m_stepLastNs = elapsedNs; 0240 if (elapsedNs > m_stepMaxNs) { 0241 m_stepMaxNs = elapsedNs; 0242 } 0243 m_stepRollingAvgNs = 0.9 * m_stepRollingAvgNs + 0.1 * elapsedNs; 0244 m_stepsSinceStart++; 0245 m_stepsSincePrint++; 0246 } 0247 } 0248 0249 void Simulator::printTimingStatistics() { 0250 qCDebug(KTL_LOG) << "Simulator::printTimingStatistics" 0251 << "m_stepMaxNs=" << m_stepMaxNs 0252 << "m_stepRollingAvgNs=" << m_stepRollingAvgNs 0253 << "m_stepLastNs=" << m_stepLastNs 0254 << "m_stepsSinceStart=" << m_stepsSinceStart 0255 << "m_stepsSincePrint=" << m_stepsSincePrint; 0256 m_stepsSincePrint = 0; 0257 } 0258 0259 void Simulator::slotSetSimulating(bool simulate) 0260 { 0261 if (m_bIsSimulating == simulate) 0262 return; 0263 0264 if (simulate) { 0265 m_stepTimer->start(SIMULATOR_STEP_INTERVAL_MS); 0266 } else { 0267 m_stepTimer->stop(); 0268 } 0269 0270 m_bIsSimulating = simulate; 0271 emit simulatingStateChanged(simulate); 0272 } 0273 0274 void Simulator::createLogicChain(LogicOut *logicOut, const LogicInList &logicInList, const PinList &pinList) 0275 { 0276 if (!logicOut) 0277 return; 0278 0279 bool state = logicOut->outputState(); 0280 0281 logicOut->setUseLogicChain(true); 0282 logicOut->pinList = pinList; 0283 logicOut->pinListBegin = logicOut->pinList.begin(); 0284 logicOut->pinListEnd = logicOut->pinList.end(); 0285 0286 LogicIn *last = logicOut; 0287 0288 const LogicInList::const_iterator end = logicInList.end(); 0289 0290 for (LogicInList::const_iterator it = logicInList.begin(); it != end; ++it) { 0291 LogicIn *next = *it; 0292 last->setNextLogic(next); 0293 last->setLastState(state); 0294 last = next; 0295 } 0296 0297 last->setNextLogic(nullptr); 0298 last->setLastState(state); 0299 0300 // Mark it as changed, if it isn't already changed... 0301 LogicOut *changed = m_pChangedLogicStart->nextChanged(m_currentChain); 0302 0303 while (changed) { 0304 if (changed == logicOut) 0305 return; 0306 0307 changed = changed->nextChanged(m_currentChain); 0308 } 0309 0310 addChangedLogic(logicOut); 0311 logicOut->setCanAddChanged(false); 0312 0313 if (!m_logicChainStarts.contains(logicOut)) 0314 m_logicChainStarts << logicOut; 0315 } 0316 0317 void Simulator::attachGpsimProcessor(GpsimProcessor *cpu) 0318 { 0319 m_gpsimProcessors->push_back(cpu); 0320 } 0321 0322 void Simulator::detachGpsimProcessor(GpsimProcessor *cpu) 0323 { 0324 m_gpsimProcessors->remove(cpu); 0325 } 0326 0327 void Simulator::attachComponentCallback(Component *component, VoidCallbackPtr function) 0328 { 0329 m_componentCallbacks->push_back(ComponentCallback(component, function)); 0330 } 0331 0332 void Simulator::attachComponent(Component *component) 0333 { 0334 if (!component || !component->doesStepNonLogic()) 0335 return; 0336 0337 m_components->push_back(component); 0338 } 0339 0340 void Simulator::detachComponent(Component *component) 0341 { 0342 m_components->remove(component); 0343 detachComponentCallbacks(*component); 0344 } 0345 0346 static Component *compx; 0347 0348 bool pred1(ComponentCallback &x) 0349 { 0350 return x.component() == compx; 0351 } 0352 0353 void Simulator::detachComponentCallbacks(Component &component) 0354 { 0355 compx = &component; 0356 m_componentCallbacks->remove_if(pred1); 0357 } 0358 0359 void Simulator::attachCircuit(Circuit *circuit) 0360 { 0361 if (!circuit) 0362 return; 0363 0364 m_ordinaryCircuits->push_back(circuit); 0365 0366 // if ( circuit->canAddChanged() ) { 0367 addChangedCircuit(circuit); 0368 circuit->setCanAddChanged(false); 0369 // } 0370 } 0371 0372 void Simulator::removeLogicInReferences(LogicIn *logicIn) 0373 { 0374 if (!logicIn) 0375 return; 0376 0377 QList<LogicOut *>::iterator end = m_logicChainStarts.end(); 0378 0379 for (QList<LogicOut *>::iterator it = m_logicChainStarts.begin(); it != end; ++it) { 0380 LogicIn *logicCallback = *it; 0381 0382 while (logicCallback) { 0383 if (logicCallback->nextLogic() == logicIn) 0384 logicCallback->setNextLogic(logicCallback->nextLogic()->nextLogic()); 0385 0386 logicCallback = logicCallback->nextLogic(); 0387 } 0388 } 0389 } 0390 0391 void Simulator::removeLogicOutReferences(LogicOut *logic) 0392 { 0393 m_logicChainStarts.removeAll(logic); 0394 0395 // Any changes to the code below will probably also apply to Simulator::detachCircuit 0396 if (m_pChangedLogicLast == logic) { 0397 LogicOut *previous_1 = nullptr; 0398 LogicOut *previous_2 = nullptr; 0399 0400 for (LogicOut *logic = m_pChangedLogicStart; logic;) { 0401 if (previous_1) 0402 previous_2 = previous_1; 0403 0404 previous_1 = logic; 0405 logic = logic->nextChanged(m_currentChain); 0406 } 0407 0408 m_pChangedLogicLast = previous_2; 0409 } 0410 0411 for (unsigned chain = 0; chain < 2; ++chain) { 0412 for (LogicOut *prevChanged = m_pChangedLogicStart; prevChanged; prevChanged = prevChanged->nextChanged(chain)) { 0413 LogicOut *nextChanged = prevChanged->nextChanged(chain); 0414 0415 if (nextChanged == logic) 0416 prevChanged->setNextChanged(nextChanged->nextChanged(chain), chain); 0417 } 0418 } 0419 } 0420 0421 void Simulator::detachCircuit(Circuit *circuit) 0422 { 0423 if (!circuit) 0424 return; 0425 0426 m_ordinaryCircuits->remove(circuit); 0427 0428 // Any changes to the code below will probably also apply to Simulator::removeLogicOutReferences 0429 0430 if (m_pChangedCircuitLast == circuit) { 0431 Circuit *previous_1 = nullptr; 0432 Circuit *previous_2 = nullptr; 0433 0434 for (Circuit *circuit = m_pChangedCircuitStart; circuit;) { 0435 if (previous_1) 0436 previous_2 = previous_1; 0437 0438 previous_1 = circuit; 0439 circuit = circuit->nextChanged(m_currentChain); 0440 } 0441 0442 m_pChangedCircuitLast = previous_2; 0443 } 0444 0445 for (unsigned chain = 0; chain < 2; ++chain) { 0446 for (Circuit *prevChanged = m_pChangedCircuitStart; prevChanged; prevChanged = prevChanged->nextChanged(chain)) { 0447 Circuit *nextChanged = prevChanged->nextChanged(chain); 0448 0449 if (nextChanged == circuit) 0450 prevChanged->setNextChanged(nextChanged->nextChanged(chain), chain); 0451 } 0452 } 0453 } 0454 0455 // END class Simulator 0456 0457 #include "moc_simulator.cpp"