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"