mirror of
https://github.com/holub/mame
synced 2025-10-04 16:34:53 +03:00
netlist: Refactored model code. (nw)
This commit is contained in:
parent
980dbcc693
commit
3320ae1f73
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 ¶m) 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 ¶m, 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 ¶m) = 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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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>;
|
||||
|
Loading…
Reference in New Issue
Block a user