/*************************************************************************** * Copyright (C) 2003-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 #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); } }