diff options
Diffstat (limited to 'src/electronics/simulation/logic.cpp')
-rw-r--r-- | src/electronics/simulation/logic.cpp | 319 |
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 * + * [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 <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); + } +} + |