/*************************************************************************** * 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"