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