You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ktechlab/src/simulator.cpp

470 lines
11 KiB

/***************************************************************************
* 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 <tqtimer.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;
TQTimer * stepTimer = new TQTimer(this);
connect( stepTimer, TQ_SIGNAL(timeout()), this, TQ_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 TQTimer),
// 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;
TQValueList<LogicOut*>::iterator end = m_logicChainStarts.end();
for ( TQValueList<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"