summaryrefslogtreecommitdiffstats
path: root/src/electronics/simulation/logic.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/electronics/simulation/logic.cpp')
-rw-r--r--src/electronics/simulation/logic.cpp319
1 files changed, 319 insertions, 0 deletions
diff --git a/src/electronics/simulation/logic.cpp b/src/electronics/simulation/logic.cpp
new file mode 100644
index 0000000..031dd2e
--- /dev/null
+++ b/src/electronics/simulation/logic.cpp
@@ -0,0 +1,319 @@
+/***************************************************************************
+ * Copyright (C) 2003-2005 by David Saxton *
+ * *
+ * 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 <vector>
+#include "circuit.h"
+#include "elementset.h"
+#include "logic.h"
+#include "matrix.h"
+#include "simulator.h"
+#include "src/core/ktlconfig.h"
+
+LogicIn::LogicIn( LogicConfig config )
+ : Element::Element()
+{
+ m_config = config;
+ m_pCallbackFunction = 0l;
+ m_numCNodes = 1;
+ m_bLastState = false;
+ m_pNextLogic = 0l;
+ setLogic(getConfig());
+}
+
+LogicIn::~LogicIn()
+{
+ Simulator::self()->removeLogicInReferences(this);
+}
+
+
+void LogicIn::setCallback( CallbackClass * object, CallbackPtr func )
+{
+ m_pCallbackFunction = func;
+ m_pCallbackObject = object;
+}
+
+
+void LogicIn::check()
+{
+ if (!b_status)
+ return;
+
+ bool newState;
+ if (m_bLastState)
+ {
+ // Was high, will still be high unless voltage is less than falling trigger
+ newState = p_cnode[0]->v > m_config.fallingTrigger;
+ }
+ else
+ {
+ // Was low, will still be low unless voltage is more than rising trigger
+ newState = p_cnode[0]->v > m_config.risingTrigger;
+ }
+
+ if ( m_pCallbackFunction && (newState != m_bLastState) )
+ {
+ m_bLastState = newState;
+ (m_pCallbackObject->*m_pCallbackFunction)(newState);
+ }
+ m_bLastState = newState;
+}
+
+
+void LogicIn::setLogic( LogicConfig config )
+{
+ m_config = config;
+ check();
+}
+
+
+void LogicIn::setElementSet( ElementSet *c )
+{
+ if (c)
+ m_pNextLogic = 0l;
+ else
+ m_cnodeI[0] = 0.;
+
+ Element::setElementSet(c);
+}
+
+
+void LogicIn::add_initial_dc()
+{
+}
+
+
+void LogicIn::updateCurrents()
+{
+}
+
+
+LogicConfig LogicIn::getConfig()
+{
+ LogicConfig c;
+ c.risingTrigger = KTLConfig::logicRisingTrigger();
+ c.fallingTrigger = KTLConfig::logicFallingTrigger();
+ c.output = KTLConfig::logicOutputHigh();
+ c.highImpedance = KTLConfig::logicOutputHighImpedance();
+ c.lowImpedance = KTLConfig::logicOutputLowImpedance();
+ return c;
+}
+
+
+LogicOut::LogicOut( LogicConfig config, bool _high )
+ : LogicIn(config)
+{
+ m_bCanAddChanged = true;
+ m_bOutputHighConductanceConst = false;
+ m_bOutputLowConductanceConst = false;
+ m_bOutputHighVoltageConst = false;
+ m_pNextChanged[0] = m_pNextChanged[1] = 0l;
+ m_pSimulator = 0l;
+ m_bUseLogicChain = false;
+ b_state = false;
+ m_numCNodes = 1;
+ m_vHigh = m_gHigh = m_gLow = 0.0;
+ m_old_g_out = m_g_out = 0.0;
+ m_old_v_out = m_v_out = 0.0;
+ setHigh(_high);
+
+ // Although we already call this function in LogicIn's constructor, our
+ // virtual function will not have got called, so we have to call it again.
+ setLogic(getConfig());
+}
+
+LogicOut::~LogicOut()
+{
+ if (!m_pSimulator)
+ m_pSimulator = Simulator::self();
+
+ // Note that although this function will get called in the destructor of
+ // LogicIn, we must call it here as well as it needs to be called before
+ // removeLogicOutReferences(this) is called.
+ m_pSimulator->removeLogicInReferences(this);
+
+ m_pSimulator->removeLogicOutReferences(this);
+}
+
+
+void LogicOut::setUseLogicChain( bool use )
+{
+ if (!m_pSimulator)
+ m_pSimulator = Simulator::self();
+
+ m_bUseLogicChain = use;
+ if (use)
+ setElementSet(0l);
+}
+
+
+void LogicOut::setElementSet( ElementSet *c )
+{
+ if (!m_pSimulator)
+ m_pSimulator = Simulator::self();
+
+ if (c)
+ {
+ m_bUseLogicChain = false;
+ m_pNextChanged[0] = m_pNextChanged[1] = 0l;
+ }
+
+ // NOTE Make sure that the next two lines are the same as those in setHigh and setLogic
+ m_g_out = b_state ? m_gHigh : m_gLow;
+ m_v_out = b_state ? m_vHigh : 0.0;
+
+ LogicIn::setElementSet(c);
+}
+
+
+void LogicOut::setOutputHighConductance( double g )
+{
+ m_bOutputHighConductanceConst = true;
+ if ( g == m_gHigh )
+ return;
+ m_gHigh = g;
+ configChanged();
+}
+
+
+void LogicOut::setOutputLowConductance( double g )
+{
+ m_bOutputLowConductanceConst = true;
+ if ( g == m_gLow )
+ return;
+ m_gLow = g;
+ configChanged();
+}
+
+
+void LogicOut::setOutputHighVoltage( double v )
+{
+ m_bOutputHighVoltageConst = true;
+ if ( v == m_vHigh )
+ return;
+ m_vHigh = v;
+ configChanged();
+}
+
+
+void LogicOut::setLogic( LogicConfig config )
+{
+ m_config = config;
+
+ if (!m_bOutputHighConductanceConst)
+ m_gHigh = 1.0/config.highImpedance;
+
+ if (!m_bOutputLowConductanceConst)
+ m_gLow = (config.lowImpedance == 0.0) ? 0.0 : 1.0/config.lowImpedance;
+
+ if (!m_bOutputHighVoltageConst)
+ m_vHigh = config.output;
+
+ configChanged();
+}
+
+
+void LogicOut::configChanged()
+{
+ if (m_bUseLogicChain)
+ return;
+
+ if (p_eSet)
+ p_eSet->setCacheInvalidated();
+
+ // Re-add the DC stuff using the new values
+
+ m_old_g_out = m_g_out;
+ m_old_v_out = m_v_out;
+
+ // NOTE Make sure that the next two lines are the same as those in setElementSet and setHigh
+ m_g_out = b_state ? m_gHigh : m_gLow;
+ m_v_out = b_state ? m_vHigh : 0.0;
+
+ add_initial_dc();
+
+ m_old_g_out = 0.;
+ m_old_v_out = 0.;
+
+ check();
+}
+
+
+void LogicOut::add_map()
+{
+ if (!b_status) return;
+
+ p_A->setUse( p_cnode[0]->n(), p_cnode[0]->n(), Map::et_variable, false );
+}
+
+
+void LogicOut::add_initial_dc()
+{
+ if (!b_status)
+ return;
+
+ A_g( 0, 0 ) += m_g_out-m_old_g_out;
+ b_i( 0 ) += m_g_out*m_v_out-m_old_g_out*m_old_v_out;
+}
+
+void LogicOut::updateCurrents()
+{
+ if (m_bUseLogicChain)
+ {
+ m_cnodeI[0] = 0.;
+ return;
+ }
+ if (!b_status) {
+ return;
+ }
+ m_cnodeI[0] = (p_cnode[0]->v-m_v_out)*m_g_out;
+}
+
+void LogicOut::setHigh( bool high )
+{
+ if ( high == b_state )
+ return;
+
+ if (m_bUseLogicChain)
+ {
+ b_state = high;
+
+ for ( LogicIn * logic = this; logic; logic = logic->nextLogic() )
+ logic->setLastState(high);
+
+ if (m_bCanAddChanged)
+ {
+ m_pSimulator->addChangedLogic(this);
+ m_bCanAddChanged = false;
+ }
+
+ return;
+ }
+
+ m_old_g_out = m_g_out;
+ m_old_v_out = m_v_out;
+
+ // NOTE Make sure that the next two lines are the same as those in setElementSet and setLogic
+ m_g_out = high ? m_gHigh : m_gLow;
+ m_v_out = high ? m_vHigh : 0.0;
+
+ add_initial_dc();
+
+ m_old_g_out = 0.;
+ m_old_v_out = 0.;
+
+ b_state = high;
+
+ if ( p_eSet && p_eSet->circuit()->canAddChanged() )
+ {
+ m_pSimulator->addChangedCircuit( p_eSet->circuit() );
+ p_eSet->circuit()->setCanAddChanged(false);
+ }
+}
+