File indexing completed on 2024-05-05 05:46:11

0001 /***************************************************************************
0002  *   Copyright (C) 2003-2006 by David Saxton                               *
0003  *   david@bluehaze.org                                                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  ***************************************************************************/
0010 
0011 #include "logic.h"
0012 #include "circuit.h"
0013 #include "elementset.h"
0014 #include "simulator.h"
0015 #include <vector>
0016 
0017 #include <ktlconfig.h>
0018 #include <ktechlab_debug.h>
0019 
0020 // BEGIN class LogicConfig
0021 LogicConfig::LogicConfig()
0022 {
0023     risingTrigger = 0.0;
0024     fallingTrigger = 0.0;
0025     output = 0.0;
0026     highImpedance = 0.0;
0027     lowImpedance = 0.0;
0028 }
0029 // END class LogicConfig
0030 
0031 // BEGIN class LogicIn
0032 LogicIn::LogicIn(LogicConfig config)
0033     : Element::Element()
0034 {
0035     m_config = config;
0036 //     m_pCallbackFunction = nullptr;
0037     m_pCallback2Func = nullptr;
0038     m_pCallback2Obj = nullptr;
0039     m_numCNodes = 1;
0040     m_bLastState = false;
0041     m_pNextLogic = nullptr;
0042     setLogic(getConfig());
0043 }
0044 
0045 LogicIn::~LogicIn()
0046 {
0047     if (Simulator::isDestroyedSim()) {
0048         return;
0049     }
0050     Simulator::self()->removeLogicInReferences(this);
0051 }
0052 
0053 // void LogicIn::setCallback(CallbackClass *object, CallbackPtr func)
0054 // {
0055 //     qCWarning(KTL_LOG) << "Callback v1 deprecated; obj=" << object << " func=" << func;
0056 //     m_pCallbackFunction = func;
0057 //     m_pCallbackObject = object;
0058 // }
0059 
0060 void LogicIn::setCallback2(Callback2Ptr fun, Callback2Obj obj)
0061 {
0062 //     if (m_pCallbackFunction && fun) {
0063 //         qCWarning(KTL_LOG) << "Callback v1 already set to " << m_pCallbackFunction << " o=" << m_pCallbackObject
0064 //             << ", forcing it to null";
0065 //         m_pCallbackFunction = nullptr;
0066 //         m_pCallbackObject = nullptr;
0067 //     }
0068     m_pCallback2Func = fun;
0069     m_pCallback2Obj = obj;
0070 }
0071 
0072 void LogicIn::check()
0073 {
0074     if (!b_status)
0075         return;
0076 
0077     bool newState;
0078     if (m_bLastState) {
0079         // Was high, will still be high unless voltage is less than falling trigger
0080         newState = p_cnode[0]->v > m_config.fallingTrigger;
0081     } else {
0082         // Was low, will still be low unless voltage is more than rising trigger
0083         newState = p_cnode[0]->v > m_config.risingTrigger;
0084     }
0085 
0086     // note: this code should be synchronized with callCallback() method
0087 //     if (m_pCallbackFunction && (newState != m_bLastState)) {
0088 //         m_bLastState = newState;
0089 //         (m_pCallbackObject->*m_pCallbackFunction)(newState);
0090 //     }
0091     if (m_pCallback2Func && (newState != m_bLastState)) {
0092         m_bLastState = newState;
0093         m_pCallback2Func(m_pCallback2Obj, newState);
0094     }
0095     m_bLastState = newState;
0096 }
0097 
0098 void LogicIn::setLogic(LogicConfig config)
0099 {
0100     m_config = config;
0101     check();
0102 }
0103 
0104 void LogicIn::setElementSet(ElementSet *c)
0105 {
0106     if (c)
0107         m_pNextLogic = nullptr;
0108     else
0109         m_cnodeI[0] = 0.;
0110 
0111     Element::setElementSet(c);
0112 }
0113 
0114 void LogicIn::add_initial_dc()
0115 {
0116 }
0117 
0118 void LogicIn::updateCurrents()
0119 {
0120 }
0121 
0122 LogicConfig LogicIn::getConfig()
0123 {
0124     LogicConfig c;
0125     c.risingTrigger = KTLConfig::logicRisingTrigger();
0126     c.fallingTrigger = KTLConfig::logicFallingTrigger();
0127     c.output = KTLConfig::logicOutputHigh();
0128     c.highImpedance = KTLConfig::logicOutputHighImpedance();
0129     c.lowImpedance = KTLConfig::logicOutputLowImpedance();
0130     return c;
0131 }
0132 // END class LogicIn
0133 
0134 // BEGIN class LogicOut
0135 LogicOut::LogicOut(LogicConfig config, bool _high)
0136     : LogicIn(config)
0137 {
0138     m_bCanAddChanged = true;
0139     m_bOutputHighConductanceConst = false;
0140     m_bOutputLowConductanceConst = false;
0141     m_bOutputHighVoltageConst = false;
0142     m_pNextChanged[0] = m_pNextChanged[1] = nullptr;
0143     m_pSimulator = nullptr;
0144     m_bUseLogicChain = false;
0145     b_state = false;
0146     m_numCNodes = 1;
0147     m_vHigh = m_gHigh = m_gLow = 0.0;
0148     m_old_g_out = m_g_out = 0.0;
0149     m_old_v_out = m_v_out = 0.0;
0150     setHigh(_high);
0151 
0152     // Although we already call this function in LogicIn's constructor, our
0153     // virtual function will not have got called, so we have to call it again.
0154     setLogic(getConfig());
0155 }
0156 
0157 LogicOut::~LogicOut()
0158 {
0159     if (Simulator::isDestroyedSim()) {
0160         return;
0161     }
0162     if (!m_pSimulator)
0163         m_pSimulator = Simulator::self();
0164 
0165     // Note that although this function will get called in the destructor of
0166     // LogicIn, we must call it here as well as it needs to be called before
0167     // removeLogicOutReferences(this) is called.
0168     m_pSimulator->removeLogicInReferences(this);
0169 
0170     m_pSimulator->removeLogicOutReferences(this);
0171 }
0172 
0173 void LogicOut::setUseLogicChain(bool use)
0174 {
0175     if (!m_pSimulator)
0176         m_pSimulator = Simulator::self();
0177 
0178     m_bUseLogicChain = use;
0179     if (use)
0180         setElementSet(nullptr);
0181 }
0182 
0183 void LogicOut::setElementSet(ElementSet *c)
0184 {
0185     if (!m_pSimulator)
0186         m_pSimulator = Simulator::self();
0187 
0188     if (c) {
0189         m_bUseLogicChain = false;
0190         m_pNextChanged[0] = m_pNextChanged[1] = nullptr;
0191     }
0192 
0193     // NOTE Make sure that the next two lines are the same as those in setHigh and setLogic
0194     m_g_out = b_state ? m_gHigh : m_gLow;
0195     m_v_out = b_state ? m_vHigh : 0.0;
0196 
0197     LogicIn::setElementSet(c);
0198 }
0199 
0200 void LogicOut::setOutputHighConductance(double g)
0201 {
0202     m_bOutputHighConductanceConst = true;
0203     if (g == m_gHigh)
0204         return;
0205     m_gHigh = g;
0206     configChanged();
0207 }
0208 
0209 void LogicOut::setOutputLowConductance(double g)
0210 {
0211     m_bOutputLowConductanceConst = true;
0212     if (g == m_gLow)
0213         return;
0214     m_gLow = g;
0215     configChanged();
0216 }
0217 
0218 void LogicOut::setOutputHighVoltage(double v)
0219 {
0220     m_bOutputHighVoltageConst = true;
0221     if (v == m_vHigh)
0222         return;
0223     m_vHigh = v;
0224     configChanged();
0225 }
0226 
0227 void LogicOut::setLogic(LogicConfig config)
0228 {
0229     m_config = config;
0230 
0231     if (!m_bOutputHighConductanceConst)
0232         m_gHigh = 1.0 / config.highImpedance;
0233 
0234     if (!m_bOutputLowConductanceConst)
0235         m_gLow = (config.lowImpedance == 0.0) ? 0.0 : 1.0 / config.lowImpedance;
0236 
0237     if (!m_bOutputHighVoltageConst)
0238         m_vHigh = config.output;
0239 
0240     configChanged();
0241 }
0242 
0243 void LogicOut::configChanged()
0244 {
0245     if (m_bUseLogicChain)
0246         return;
0247 
0248     if (p_eSet)
0249         p_eSet->setCacheInvalidated();
0250 
0251     // Re-add the DC stuff using the new values
0252 
0253     m_old_g_out = m_g_out;
0254     m_old_v_out = m_v_out;
0255 
0256     // NOTE Make sure that the next two lines are the same as those in setElementSet and setHigh
0257     m_g_out = b_state ? m_gHigh : m_gLow;
0258     m_v_out = b_state ? m_vHigh : 0.0;
0259 
0260     add_initial_dc();
0261 
0262     m_old_g_out = 0.;
0263     m_old_v_out = 0.;
0264 
0265     check();
0266 }
0267 
0268 void LogicOut::add_initial_dc()
0269 {
0270     if (!b_status)
0271         return;
0272 
0273     A_g(0, 0) += m_g_out - m_old_g_out;
0274     b_i(0) += m_g_out * m_v_out - m_old_g_out * m_old_v_out;
0275 }
0276 
0277 void LogicOut::updateCurrents()
0278 {
0279     if (m_bUseLogicChain) {
0280         m_cnodeI[0] = 0.0;
0281         return;
0282     }
0283     if (!b_status)
0284         return;
0285 
0286     m_cnodeI[0] = (m_v_out - p_cnode[0]->v) * m_g_out;
0287 }
0288 
0289 void LogicOut::setHigh(bool high)
0290 {
0291     if (high == b_state)
0292         return;
0293 
0294     if (m_bUseLogicChain) {
0295         b_state = high;
0296 
0297         for (LogicIn *logic = this; logic; logic = logic->nextLogic())
0298             logic->setLastState(high);
0299 
0300         if (m_bCanAddChanged) {
0301             m_pSimulator->addChangedLogic(this);
0302             m_bCanAddChanged = false;
0303         }
0304 
0305         return;
0306     }
0307 
0308     m_old_g_out = m_g_out;
0309     m_old_v_out = m_v_out;
0310 
0311     // NOTE Make sure that the next two lines are the same as those in setElementSet and setLogic
0312     m_g_out = high ? m_gHigh : m_gLow;
0313     m_v_out = high ? m_vHigh : 0.0;
0314 
0315     add_initial_dc();
0316 
0317     m_old_g_out = 0.;
0318     m_old_v_out = 0.;
0319 
0320     b_state = high;
0321 
0322     if (p_eSet && p_eSet->circuit()->canAddChanged()) {
0323         m_pSimulator->addChangedCircuit(p_eSet->circuit());
0324         p_eSet->circuit()->setCanAddChanged(false);
0325     }
0326 }
0327 // END class LogicOut