diff options
Diffstat (limited to 'src/simulator.cpp')
-rw-r--r-- | src/simulator.cpp | 469 |
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 * + * [email protected] * + * * + * 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" |