You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
320 lines
6.4 KiB
320 lines
6.4 KiB
/***************************************************************************
|
|
* 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 <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);
|
|
}
|
|
}
|
|
|