summaryrefslogtreecommitdiffstats
path: root/src/simulator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/simulator.cpp')
-rw-r--r--src/simulator.cpp469
1 files changed, 469 insertions, 0 deletions
diff --git a/src/simulator.cpp b/src/simulator.cpp
new file mode 100644
index 0000000..c0f406d
--- /dev/null
+++ b/src/simulator.cpp
@@ -0,0 +1,469 @@
+/***************************************************************************
+ * Copyright (C) 2005 by David Saxton *
+ * david@bluehaze.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "component.h"
+#include "gpsimprocessor.h"
+#include "pin.h"
+#include "simulator.h"
+#include "switch.h"
+
+#include <kstaticdeleter.h>
+#include <qtimer.h>
+
+
+//BEGIN class Simulator
+Simulator * Simulator::m_pSelf = 0l;
+static KStaticDeleter<Simulator> staticSimulatorDeleter;
+
+Simulator * Simulator::self()
+{
+ if (!m_pSelf)
+ staticSimulatorDeleter.setObject( m_pSelf, new Simulator() );
+ return m_pSelf;
+}
+
+
+Simulator::Simulator()
+{
+ m_currentChain = 0;
+ m_llNumber = 0;
+ m_stepNumber = 0;
+ m_bIsSimulating = true;
+ m_gpsimProcessors = 0l;
+ m_componentCallbacks = 0l;
+ m_components = 0l;
+ m_ordinaryCircuits = 0l;
+ m_switches = 0l;
+
+ unsigned max = unsigned(LOGIC_UPDATE_RATE/LINEAR_UPDATE_RATE);
+ for ( unsigned i = 0; i < max; i++ )
+ {
+ m_pStartStepCallback[i] = 0l;
+ m_pNextStepCallback[i] = 0l;
+ }
+
+ LogicConfig lc;
+ m_pChangedLogicStart = new LogicOut( lc, false );
+ m_pChangedLogicLast = m_pChangedLogicStart;
+
+ m_pChangedCircuitStart = new Circuit;
+ m_pChangedCircuitLast = m_pChangedCircuitStart;
+
+ QTimer * stepTimer = new QTimer(this);
+ connect( stepTimer, SIGNAL(timeout()), this, SLOT(step()) );
+ stepTimer->start(1);
+}
+
+
+Simulator::~Simulator()
+{
+ delete m_pChangedLogicStart;
+ delete m_pChangedCircuitStart;
+
+ detachAll(m_gpsimProcessors);
+ detachAll(m_components);
+ detachAll(m_componentCallbacks);
+ detachAll(m_ordinaryCircuits);
+ detachAll(m_switches);
+}
+
+
+void Simulator::step()
+{
+ if (!m_bIsSimulating)
+ return;
+
+ // We are called a thousand times a second (the maximum allowed by QTimer),
+ // so divide the LINEAR_UPDATE_RATE by 1e3 for the number of loops we need
+ // to do.
+ const unsigned maxSteps = unsigned(LINEAR_UPDATE_RATE/1e3);
+ for ( unsigned i = 0; i < maxSteps; ++i )
+ {
+ m_llNumber = 0;
+ m_stepNumber++;
+
+ // Update the non-logic parts of the simulation
+ LinkedList<Component> * component = m_components;
+ while (component)
+ {
+ component->data()->stepNonLogic();
+ component = component->m_pNext;
+ }
+ LinkedList<Circuit> * circuit = m_ordinaryCircuits;
+ while (circuit)
+ {
+ circuit->data()->doNonLogic();
+ circuit = circuit->m_pNext;
+ }
+ LinkedList<Switch> * sw = m_switches;
+ while (sw)
+ {
+ sw->data()->bounce();
+ sw = sw->m_pNext;
+ }
+
+ // Update the logic parts of our simulation
+ const unsigned max = unsigned(LOGIC_UPDATE_RATE/LINEAR_UPDATE_RATE);
+ for ( m_llNumber = 0; m_llNumber < max; ++m_llNumber )
+ {
+ // Update the logic components
+ LinkedList<ComponentCallback> * callback = m_componentCallbacks;
+ while (callback)
+ {
+ callback->data()->callback();
+ callback = callback->m_pNext;
+ }
+
+ callback = m_pStartStepCallback[m_llNumber];
+ while (callback)
+ {
+ LinkedList<ComponentCallback> * next = callback->m_pNext;
+ callback->m_pNext = 0l;
+ callback->data()->callback();
+ callback = next;
+ }
+ m_pStartStepCallback[m_llNumber] = 0l;
+
+#ifndef NO_GPSIM
+ // Update the gpsim processors
+ LinkedList<GpsimProcessor> * gpsimProcessor = m_gpsimProcessors;
+ while (gpsimProcessor)
+ {
+ gpsimProcessor->data()->executeNext();
+ gpsimProcessor = gpsimProcessor->m_pNext;
+ }
+#endif
+
+
+ int prevChain = m_currentChain;
+ m_currentChain = 1 - m_currentChain;
+
+
+ // Update the non-logic circuits
+ if ( Circuit * changed = m_pChangedCircuitStart->nextChanged(prevChain) )
+ {
+ for ( Circuit * circuit = changed; circuit; circuit = circuit->nextChanged(prevChain) )
+ circuit->setCanAddChanged(true);
+
+ m_pChangedCircuitStart->setNextChanged( 0l, prevChain );
+ m_pChangedCircuitLast = m_pChangedCircuitStart;
+
+ do
+ {
+ Circuit * next = changed->nextChanged(prevChain);
+ changed->setNextChanged( 0l, prevChain );
+ changed->doLogic();
+ changed = next;
+ }
+ while (changed);
+ }
+
+ // Call the logic callbacks
+ if (LogicOut * changed = m_pChangedLogicStart->nextChanged(prevChain))
+ {
+ for ( LogicOut * out = changed; out; out = out->nextChanged(prevChain) )
+ out->setCanAddChanged(true);
+
+ m_pChangedLogicStart->setNextChanged( 0l, prevChain );
+ m_pChangedLogicLast = m_pChangedLogicStart;
+ do
+ {
+ LogicOut * next = changed->nextChanged(prevChain);
+ changed->setNextChanged( 0l, prevChain );
+
+ double v = changed->isHigh() ? changed->outputHighVoltage() : 0.0;
+
+ for ( PinList::iterator it = changed->pinListBegin; it != changed->pinListEnd; ++it )
+ {
+ if ( Pin * pin = *it )
+ pin->setVoltage(v);
+ }
+
+ LogicIn * logicCallback = changed;
+ while (logicCallback)
+ {
+ logicCallback->callCallback();
+ logicCallback = logicCallback->nextLogic();
+ }
+
+ changed = next;
+ }
+ while (changed);
+ }
+ }
+ }
+}
+
+
+void Simulator::slotSetSimulating( bool simulate )
+{
+ if ( m_bIsSimulating == simulate )
+ return;
+
+ m_bIsSimulating = simulate;
+ emit simulatingStateChanged(simulate);
+}
+
+
+void Simulator::createLogicChain( LogicOut * logicOut, const LogicInList & logicInList, const PinList & pinList )
+{
+ if (!logicOut)
+ return;
+
+ bool state = logicOut->outputState();
+
+ logicOut->setUseLogicChain(true);
+ logicOut->pinList = pinList;
+ logicOut->pinListBegin = logicOut->pinList.begin();
+ logicOut->pinListEnd = logicOut->pinList.end();
+
+ LogicIn * last = logicOut;
+ const LogicInList::const_iterator end = logicInList.end();
+ for ( LogicInList::const_iterator it = logicInList.begin(); it != end; ++it )
+ {
+ LogicIn * next = *it;
+ last->setNextLogic(next);
+ last->setLastState(state);
+ last = next;
+ }
+ last->setNextLogic(0l);
+ last->setLastState(state);
+
+ // Mark it as changed, if it isn't already changed...
+ LogicOut * changed = m_pChangedLogicStart->nextChanged(m_currentChain);
+ while (changed)
+ {
+ if ( changed == logicOut )
+ return;
+ changed = changed->nextChanged(m_currentChain);
+ }
+ addChangedLogic(logicOut);
+ logicOut->setCanAddChanged(false);
+
+ if ( !m_logicChainStarts.contains( logicOut ) )
+ m_logicChainStarts << logicOut;
+}
+
+
+template <typename T>
+void Simulator::attach( LinkedList<T> ** start, T * data )
+{
+ if (!data)
+ return;
+
+ while ( *start && (*start)->m_pNext )
+ {
+ if ( (*start)->data() == data )
+ return;
+ start = & (*start)->m_pNext;
+ }
+
+ if (*start)
+ (*start)->m_pNext = new LinkedList<T>(data);
+ else
+ *start = new LinkedList<T>(data);
+}
+
+
+template <typename T>
+void Simulator::detach( LinkedList<T> ** start, T * data )
+{
+ if (!data)
+ return;
+
+ while (*start)
+ {
+ if ( (*start)->data() == data )
+ {
+ LinkedList<T> * toDelete = *start;
+ *start = (*start)->m_pNext;
+ delete toDelete;
+ return;
+ }
+
+ start = & (*start)->m_pNext;
+ }
+}
+
+
+template <typename T>
+void Simulator::detachAll( LinkedList<T> * list )
+{
+ while (list)
+ {
+ LinkedList<T> * next = list->m_pNext;
+ delete list;
+ list = next;
+ }
+}
+
+
+void Simulator::attachGpsimProcessor( GpsimProcessor * cpu )
+{
+ attach( & m_gpsimProcessors, cpu );
+}
+
+
+void Simulator::detachGpsimProcessor( GpsimProcessor * cpu )
+{
+ detach( & m_gpsimProcessors, cpu );
+}
+
+
+void Simulator::attachComponentCallback( Component * component, VoidCallbackPtr function )
+{
+ attach( & m_componentCallbacks, new ComponentCallback( component, function ) );
+}
+
+
+void Simulator::attachComponent( Component * component )
+{
+ if ( !component || !component->doesStepNonLogic() )
+ return;
+
+ attach( & m_components, component );
+}
+
+
+void Simulator::detachComponent( Component * component )
+{
+ detach( & m_components, component );
+ detachComponentCallbacks(component);
+}
+
+
+void Simulator::attachSwitch( Switch * sw )
+{
+ attach( & m_switches, sw );
+}
+
+
+void Simulator::detachSwitch( Switch * sw )
+{
+ detach( & m_switches, sw );
+}
+
+
+void Simulator::detachComponentCallbacks( Component * component )
+{
+ LinkedList<ComponentCallback> * callback = m_componentCallbacks;
+ while (callback)
+ {
+ LinkedList<ComponentCallback> * next = callback->m_pNext;
+ ComponentCallback * data = callback->data();
+ if ( data->component() == component )
+ {
+ detach( & m_componentCallbacks, data );
+ delete data;
+ }
+ callback = next;
+ }
+}
+
+
+void Simulator::attachCircuit( Circuit * circuit )
+{
+ if (!circuit)
+ return;
+ attach( & m_ordinaryCircuits, circuit );
+ addChangedCircuit(circuit);
+ circuit->setCanAddChanged(false);
+}
+
+
+void Simulator::removeLogicInReferences( LogicIn * logicIn )
+{
+ if ( !logicIn )
+ return;
+
+ QValueList<LogicOut*>::iterator end = m_logicChainStarts.end();
+ for ( QValueList<LogicOut*>::iterator it = m_logicChainStarts.begin(); it != end; ++it )
+ {
+ LogicIn * logicCallback = *it;
+ while (logicCallback)
+ {
+ if ( logicCallback->nextLogic() == logicIn )
+ logicCallback->setNextLogic( logicCallback->nextLogic()->nextLogic() );
+ logicCallback = logicCallback->nextLogic();
+ }
+ }
+}
+
+
+void Simulator::removeLogicOutReferences( LogicOut * logic )
+{
+ m_logicChainStarts.remove( logic );
+
+ // Any changes to the code below will probably also apply to Simulator::detachCircuit
+
+ if ( m_pChangedLogicLast == logic )
+ {
+ LogicOut * previous_1 = 0l;
+ LogicOut * previous_2 = 0l;
+ for ( LogicOut * logic = m_pChangedLogicStart; logic; )
+ {
+ if (previous_1)
+ previous_2 = previous_1;
+ previous_1 = logic;
+ logic = logic->nextChanged( m_currentChain );
+ }
+
+ m_pChangedLogicLast = previous_2;
+ }
+
+ for ( unsigned chain = 0; chain < 2; ++chain )
+ {
+ for ( LogicOut * prevChanged = m_pChangedLogicStart; prevChanged; prevChanged = prevChanged->nextChanged( chain ) )
+ {
+ LogicOut * nextChanged = prevChanged->nextChanged( chain );
+ if ( nextChanged == logic )
+ prevChanged->setNextChanged( nextChanged->nextChanged( chain ), chain );
+ }
+ }
+}
+
+
+void Simulator::detachCircuit( Circuit * circuit )
+{
+ if (!circuit)
+ return;
+
+ detach( & m_ordinaryCircuits, circuit );
+
+ // Any changes to the code below will probably also apply to Simulator::removeLogicOutReferences
+
+ if ( m_pChangedCircuitLast == circuit )
+ {
+ Circuit * previous_1 = 0l;
+ Circuit * previous_2 = 0l;
+ for ( Circuit * circuit = m_pChangedCircuitStart; circuit; )
+ {
+ if (previous_1)
+ previous_2 = previous_1;
+ previous_1 = circuit;
+ circuit = circuit->nextChanged( m_currentChain );
+ }
+
+ m_pChangedCircuitLast = previous_2;
+ }
+
+ for ( unsigned chain = 0; chain < 2; ++chain )
+ {
+ for ( Circuit * prevChanged = m_pChangedCircuitStart; prevChanged; prevChanged = prevChanged->nextChanged( chain ) )
+ {
+ Circuit * nextChanged = prevChanged->nextChanged( chain );
+ if ( nextChanged == circuit )
+ prevChanged->setNextChanged( nextChanged->nextChanged( chain ), chain );
+ }
+ }
+}
+//END class Simulator
+
+#include "simulator.moc"