netlist: Refactored model code. (nw)

This commit is contained in:
couriersud 2019-03-31 19:37:02 +02:00
parent 980dbcc693
commit 3320ae1f73
7 changed files with 108 additions and 112 deletions

View File

@ -341,7 +341,7 @@ namespace analog
nl_double NF = m_model.m_NF;
//nl_double VJE = m_model.dValue("VJE", 0.75);
set_qtype((m_model.model_type() == "NPN") ? BJT_NPN : BJT_PNP);
set_qtype((m_model.type() == "NPN") ? BJT_NPN : BJT_PNP);
nl_double alpha = BF / (1.0 + BF);
@ -446,7 +446,7 @@ namespace analog
nl_double NR = m_model.m_NR;
//nl_double VJE = m_model.dValue("VJE", 0.75);
set_qtype((m_model.model_type() == "NPN") ? BJT_NPN : BJT_PNP);
set_qtype((m_model.type() == "NPN") ? BJT_NPN : BJT_PNP);
m_alpha_f = BF / (1.0 + BF);
m_alpha_r = BR / (1.0 + BR);

View File

@ -219,14 +219,76 @@ namespace analog
connect(m_SG.m_N, m_DG.m_N);
connect(m_DG.m_P, m_SD.m_N);
set_qtype((m_model.model_type() == "NMOS_DEFAULT") ? FET_NMOS : FET_PMOS);
set_qtype((m_model.type() == "NMOS_DEFAULT") ? FET_NMOS : FET_PMOS);
m_polarity = qtype() == FET_NMOS ? 1.0 : -1.0;
m_capmod = m_model.m_CAPMOD;
// printf("capmod %d %g %g\n", m_capmod, (double)m_model.m_VTO, m_polarity);
nl_assert_always(m_capmod == 0 || m_capmod == 2, "Error: CAPMODEL invalid value for " + m_model.name());
//printf("%g\n", exec().solver()->gmin());
/*
* From http://ltwiki.org/LTspiceHelp/LTspiceHelp/M_MOSFET.htm :
*
* VTO, KP, LAMBDA, PHI and GAMMA. These parameters are computed
* if the process parameters(NSUB, TOX,...) are given, but
* user-specified values always override.
*
* But couldn't find a formula for lambda anywhere
*
*/
m_lambda = m_model.m_LAMBDA; // FIXME: m_lambda only set once
// calculate effective channel length
m_Leff = m_model.m_L - 2 * m_model.m_LD;
nl_assert_always(m_Leff > 0.0, "Effective Lateral diffusion would be negative for model " + m_model.name());
nl_double Cox = (m_model.m_TOX > 0.0) ? (constants::eps_SiO2() * constants::eps_0() / m_model.m_TOX) : 0.0;
// calculate DC transconductance coefficient
if (m_model.m_KP > 0)
m_beta = m_model.m_KP * m_model.m_W / m_Leff;
else if (Cox > 0 && m_model.m_UO > 0)
m_beta = m_model.m_UO * 1e-4 * Cox * m_model.m_W / m_Leff;
else
m_beta = 2e-5 * m_model.m_W / m_Leff;
//FIXME::UT can disappear
const double Vt = constants::T0() * constants::k_b() / constants::Q_e();
// calculate surface potential if not given
if (m_model.m_PHI > 0.0)
m_phi = m_model.m_PHI;
else if (m_model.m_NSUB > 0.0)
{
nl_assert_always(m_model.m_NSUB * 1e6 >= constants::NiSi(), "Error calculating phi for model " + m_model.name());
m_phi = 2 * Vt * std::log (m_model.m_NSUB * 1e6 / constants::NiSi());
}
else
m_phi = 0.6;
// calculate bulk threshold if not given
if (m_model.m_GAMMA > 0.0)
m_gamma = m_model.m_GAMMA;
else
{
if (Cox > 0.0 && m_model.m_NSUB > 0)
m_gamma = std::sqrt (2.0 * constants::Q_e() * constants::eps_Si() * constants::eps_0() * m_model.m_NSUB * 1e6) / Cox;
else
m_gamma = 0.0;
}
m_vto = m_model.m_VTO;
nl_assert_always(m_vto != 0.0, "Threshold voltage not specified for " + m_model.name());
/* FIXME: VTO if missing may be calculated from TPG, NSS and temperature. Usually models
* specify VTO so skip this here.
*/
m_CoxWL = Cox * m_model.m_W * m_Leff;
//printf("Cox: %g\n", m_Cox);
}
NETLIB_IS_TIMESTEP(true || m_capmod != 0)
@ -250,7 +312,17 @@ namespace analog
protected:
NETLIB_RESETI();
NETLIB_RESETI()
{
NETLIB_NAME(FET)::reset();
// Bulk diodes
m_D_BD.set_param(m_model.m_ISD, m_model.m_N, exec().gmin(), constants::T0());
#if (!BODY_CONNECTED_TO_SOURCE)
m_D_BS.set_param(m_model.m_ISS, m_model.m_N, exec().gmin(), constants::T0());
#endif
}
NETLIB_UPDATEI();
NETLIB_UPDATE_PARAMI();
NETLIB_UPDATE_TERMINALSI();
@ -353,7 +425,7 @@ namespace analog
};
// ----------------------------------------------------------------------------------------
// nld_Q - Ebers Moll
// MOSFET
// ----------------------------------------------------------------------------------------
NETLIB_UPDATE(MOSFET)
@ -366,11 +438,6 @@ namespace analog
m_DG.m_N.solve_now(); // Collector
}
NETLIB_RESET(MOSFET)
{
NETLIB_NAME(FET)::reset();
}
NETLIB_UPDATE_TERMINALS(MOSFET)
{
nl_double Vgd = -m_DG.deltaV() * m_polarity; // Gate - Drain
@ -522,77 +589,6 @@ namespace analog
NETLIB_UPDATE_PARAM(MOSFET)
{
/*
* From http://ltwiki.org/LTspiceHelp/LTspiceHelp/M_MOSFET.htm :
*
* VTO, KP, LAMBDA, PHI and GAMMA. These parameters are computed
* if the process parameters(NSUB, TOX,...) are given, but
* user-specified values always override.
*
* But couldn't find a formula for lambda anywhere
*
*/
m_lambda = m_model.m_LAMBDA; // FIXME: m_lambda only set once
// calculate effective channel length
m_Leff = m_model.m_L - 2 * m_model.m_LD;
nl_assert_always(m_Leff > 0.0, "Effective Lateral diffusion would be negative for model " + m_model.name());
nl_double Cox = (m_model.m_TOX > 0.0) ? (constants::eps_SiO2() * constants::eps_0() / m_model.m_TOX) : 0.0;
// calculate DC transconductance coefficient
if (m_model.m_KP > 0)
m_beta = m_model.m_KP * m_model.m_W / m_Leff;
else if (Cox > 0 && m_model.m_UO > 0)
m_beta = m_model.m_UO * 1e-4 * Cox * m_model.m_W / m_Leff;
else
m_beta = 2e-5 * m_model.m_W / m_Leff;
// Bulk diodes
m_D_BD.set_param(m_model.m_ISD, m_model.m_N, exec().gmin(), constants::T0());
#if (!BODY_CONNECTED_TO_SOURCE)
m_D_BS.set_param(m_model.m_ISS, m_model.m_N, exec().gmin(), constants::T0());
#endif
//FIXME::UT can disappear
const double Vt = constants::T0() * constants::k_b() / constants::Q_e();
// calculate surface potential if not given
if (m_model.m_PHI > 0.0)
m_phi = m_model.m_PHI;
else if (m_model.m_NSUB > 0.0)
{
nl_assert_always(m_model.m_NSUB * 1e6 >= constants::NiSi(), "Error calculating phi for model " + m_model.name());
m_phi = 2 * Vt * std::log (m_model.m_NSUB * 1e6 / constants::NiSi());
}
else
m_phi = 0.6;
// calculate bulk threshold if not given
if (m_model.m_GAMMA > 0.0)
m_gamma = m_model.m_GAMMA;
else
{
if (Cox > 0.0 && m_model.m_NSUB > 0)
m_gamma = std::sqrt (2.0 * constants::Q_e() * constants::eps_Si() * constants::eps_0() * m_model.m_NSUB * 1e6) / Cox;
else
m_gamma = 0.0;
}
m_vto = m_model.m_VTO;
nl_assert_always(m_vto != 0.0, "Threshold voltage not specified for " + m_model.name());
/* FIXME: VTO if missing may be calculated from TPG, NSS and temperature. Usually models
* specify VTO so skip this here.
*/
m_CoxWL = Cox * m_model.m_W * m_Leff;
//printf("Cox: %g\n", m_Cox);
}
} // namespace analog

View File

@ -28,7 +28,7 @@ space :=
space +=
TIDY_FLAGS = $(subst $(space),,$(TIDY_FLAGSX))
TIDY_FLAGS = -checks=llvm-include-order,llvm-namespace-comment,modernize-use-override,modernize-use-using -fix
#TIDY_FLAGS = -checks=llvm-include-order,llvm-namespace-comment,modernize-use-override,modernize-use-using -fix
#TIDY_FLAGS = -checks=llvm-include-order -fix
#TIDY_FLAGS = -checks=llvm-namespace-comment -fix
#TIDY_FLAGS = -checks=modernize-use-override -fix

View File

@ -988,9 +988,9 @@ pstring param_t::get_initial(const device_t &dev, bool *found)
return res;
}
const pstring param_model_t::model_type()
const pstring param_model_t::type()
{
return state().setup().models().model_type(value());
return state().setup().models().type(str());
}
param_str_t::param_str_t(device_t &device, const pstring &name, const pstring &val)
@ -1015,20 +1015,20 @@ void param_model_t::changed()
state().log().fatal(MF_1_MODEL_1_CAN_NOT_BE_CHANGED_AT_RUNTIME, name());
}
const pstring param_model_t::model_value_str(const pstring &entity)
const pstring param_model_t::value_str(const pstring &entity)
{
return state().setup().models().model_value_str(value(), entity);
return state().setup().models().value_str(str(), entity);
}
nl_double param_model_t::model_value(const pstring &entity)
nl_double param_model_t::value(const pstring &entity)
{
return state().setup().models().model_value(value(), entity);
return state().setup().models().value(str(), entity);
}
plib::unique_ptr<plib::pistream> param_data_t::stream()
{
return device().setup().get_data_stream(value());
return device().setup().get_data_stream(str());
}
bool detail::core_terminal_t::is_logic() const NL_NOEXCEPT

View File

@ -1010,7 +1010,7 @@ namespace netlist
public:
param_str_t(device_t &device, const pstring &name, const pstring &val);
const pstring &operator()() const NL_NOEXCEPT { return value(); }
const pstring &operator()() const NL_NOEXCEPT { return str(); }
void setTo(const pstring &param) NL_NOEXCEPT
{
if (m_param != param)
@ -1022,7 +1022,7 @@ namespace netlist
}
protected:
virtual void changed();
const pstring &value() const NL_NOEXCEPT { return m_param; }
const pstring &str() const NL_NOEXCEPT { return m_param; }
private:
PALIGNAS_CACHELINE()
pstring m_param;
@ -1041,7 +1041,7 @@ namespace netlist
{
public:
value_base_t(param_model_t &param, const pstring &name)
: m_value(static_cast<T>(param.model_value(name)))
: m_value(static_cast<T>(param.value(name)))
{
}
T operator()() const noexcept { return m_value; }
@ -1058,13 +1058,13 @@ namespace netlist
param_model_t(device_t &device, const pstring &name, const pstring &val)
: param_str_t(device, name, val) { }
const pstring model_value_str(const pstring &entity) /*const*/;
const pstring model_type() /*const*/;
const pstring value_str(const pstring &entity) /*const*/;
nl_double value(const pstring &entity) /*const*/;
const pstring type() /*const*/;
/* hide this */
void setTo(const pstring &param) = delete;
protected:
void changed() override;
nl_double model_value(const pstring &entity) /*const*/;
private:
};
@ -1562,7 +1562,7 @@ namespace netlist
if (f != nullptr)
f->read(reinterpret_cast<plib::pistream::value_type *>(&m_data[0]),1<<AW);
else
device.state().log().warning("Rom {1} not found", value());
device.state().log().warning("Rom {1} not found", str());
}
inline void logic_input_t::inactivate() NL_NOEXCEPT

View File

@ -877,7 +877,7 @@ pstring models_t::model_string(model_map_t &map)
return ret + ")";
}
pstring models_t::model_value_str(pstring model, pstring entity)
pstring models_t::value_str(pstring model, pstring entity)
{
model_map_t &map = m_cache[model];
@ -897,14 +897,14 @@ pstring models_t::model_value_str(pstring model, pstring entity)
return ret;
}
nl_double models_t::model_value(pstring model, pstring entity)
nl_double models_t::value(pstring model, pstring entity)
{
model_map_t &map = m_cache[model];
if (map.size() == 0)
model_parse(model , map);
pstring tmp = model_value_str(model, entity);
pstring tmp = value_str(model, entity);
nl_double factor = plib::constants<nl_double>::one();
auto p = std::next(tmp.begin(), static_cast<pstring::difference_type>(tmp.size() - 1));
@ -952,9 +952,9 @@ pool_owned_ptr<devices::nld_base_a_to_d_proxy> logic_family_std_proxy_t::create_
const logic_family_desc_t *setup_t::family_from_model(const pstring &model)
{
if (m_models.model_value_str(model, "TYPE") == "TTL")
if (m_models.value_str(model, "TYPE") == "TTL")
return family_TTL();
if (m_models.model_value_str(model, "TYPE") == "CD4XXX")
if (m_models.value_str(model, "TYPE") == "CD4XXX")
return family_CD4XXX();
for (auto & e : m_nlstate.m_family_cache)
@ -963,13 +963,13 @@ const logic_family_desc_t *setup_t::family_from_model(const pstring &model)
auto ret = plib::make_unique<logic_family_std_proxy_t>();
ret->m_fixed_V = m_models.model_value(model, "FV");
ret->m_low_thresh_PCNT = m_models.model_value(model, "IVL");
ret->m_high_thresh_PCNT = m_models.model_value(model, "IVH");
ret->m_low_VO = m_models.model_value(model, "OVL");
ret->m_high_VO = m_models. model_value(model, "OVH");
ret->m_R_low = m_models.model_value(model, "ORL");
ret->m_R_high = m_models.model_value(model, "ORH");
ret->m_fixed_V = m_models.value(model, "FV");
ret->m_low_thresh_PCNT = m_models.value(model, "IVL");
ret->m_high_thresh_PCNT = m_models.value(model, "IVH");
ret->m_low_VO = m_models.value(model, "OVL");
ret->m_high_VO = m_models. value(model, "OVH");
ret->m_R_low = m_models.value(model, "ORL");
ret->m_R_high = m_models.value(model, "ORH");
auto retp = ret.get();

View File

@ -213,11 +213,11 @@ namespace netlist
void register_model(pstring model_in);
/* model / family related */
pstring model_value_str(pstring model, pstring entity);
pstring value_str(pstring model, pstring entity);
double model_value(pstring model, pstring entity);
nl_double value(pstring model, pstring entity);
pstring model_type(pstring model) { return model_value_str(model, "COREMODEL"); }
pstring type(pstring model) { return value_str(model, "COREMODEL"); }
private:
using model_map_t = std::unordered_map<pstring, pstring>;