netlist: Parameters evaluated when netlist is created. [Couriersud]

Parameters are now passed to the netlist core as strings. During netlist
creation they are evaluated as functions. This opens the path to
parameters on subdevice level.

Examples:

PARAM(device.XY, (1+2*0.005))
RES(R1, 2.05*RES_K(1)+1)

In addition the commit contains dead code removal.
This commit is contained in:
couriersud 2020-01-29 19:00:10 +01:00
parent d7fd89afe1
commit fceee50c8b
10 changed files with 34 additions and 94 deletions

View File

@ -991,9 +991,9 @@ void netlist_mame_stream_input_device::custom_netlist_additions(netlist::netlist
pstring sparam = plib::pfmt("STREAM_INPUT.CHAN{1}")(m_channel);
nlstate.setup().register_param(sparam, pstring(m_param_name));
sparam = plib::pfmt("STREAM_INPUT.MULT{1}")(m_channel);
nlstate.setup().register_param(sparam, m_mult);
nlstate.setup().register_param_val(sparam, m_mult);
sparam = plib::pfmt("STREAM_INPUT.OFFSET{1}")(m_channel);
nlstate.setup().register_param(sparam, m_offset);
nlstate.setup().register_param_val(sparam, m_offset);
}
// ----------------------------------------------------------------------------------------
@ -1027,9 +1027,9 @@ void netlist_mame_stream_output_device::custom_netlist_additions(netlist::netlis
//snd_out = dynamic_cast<NETLIB_NAME(sound_out) *>(setup.register_dev("nld_sound_out", sname));
nlstate.setup().register_dev("NETDEV_SOUND_OUT", sname);
nlstate.setup().register_param(sname + ".CHAN" , m_channel);
nlstate.setup().register_param(sname + ".MULT", m_mult);
nlstate.setup().register_param(sname + ".OFFSET", m_offset);
nlstate.setup().register_param_val(sname + ".CHAN" , m_channel);
nlstate.setup().register_param_val(sname + ".MULT", m_mult);
nlstate.setup().register_param_val(sname + ".OFFSET", m_offset);
nlstate.setup().register_link(sname + ".IN", pstring(m_out_name));
}

View File

@ -138,11 +138,9 @@ namespace analog
, m_Vmin(nlconst::zero()) // not used in MOS model
, m_Is(nlconst::zero())
, m_logIs(nlconst::zero())
, m_n(nlconst::zero())
, m_gmin(nlconst::magic(1e-15))
, m_VtInv(nlconst::zero())
, m_Vcrit(nlconst::zero())
, m_name(name)
{
set_param(
nlconst::magic(1e-15)
@ -205,10 +203,9 @@ namespace analog
{
m_Is = Is;
m_logIs = plib::log(Is);
m_n = n;
m_gmin = gmin;
m_Vt = m_n * temp * nlconst::k_b() / nlconst::Q_e();
m_Vt = n * temp * nlconst::k_b() / nlconst::Q_e();
m_Vmin = nlconst::magic(-5.0) * m_Vt;
@ -234,13 +231,10 @@ namespace analog
nl_fptype m_Vmin;
nl_fptype m_Is;
nl_fptype m_logIs;
nl_fptype m_n;
nl_fptype m_gmin;
nl_fptype m_VtInv;
nl_fptype m_Vcrit;
pstring m_name;
};

View File

@ -43,8 +43,7 @@
#else
#define SOLVER(name, freq) \
NET_REGISTER_DEV(SOLVER, name) \
PARAM(name.FREQ, freq)
NET_REGISTER_DEVEXT(SOLVER, name, freq)
#include "nld_system.h"

View File

@ -215,7 +215,6 @@ namespace netlist
// Add default include file
using a = plib::psource_str_t<plib::psource_t>;
#if USE_EVAL
const pstring content =
"#define RES_R(res) (res) \n"
"#define RES_K(res) ((res) * 1e3) \n"
@ -227,9 +226,6 @@ namespace netlist
"#define IND_N(ind) ((ind) * 1e-9) \n"
"#define IND_P(ind) ((ind) * 1e-12) \n";
setup().add_include(plib::make_unique<a>("netlist/devices/net_lib.h", content));
#else
setup().add_include(plib::make_unique<a>("netlist/devices/net_lib.h",""));
#endif
NETLIST_NAME(base)(*m_setup);
}

View File

@ -10,9 +10,6 @@
#include "plib/pconfig.h"
#include "plib/pexception.h"
// FIXME: Remove this again after testing
#define USE_EVAL (0)
///
/// \brief Version - Major.
///
@ -20,7 +17,7 @@
///
/// \brief Version - Minor.
///
#define NL_VERSION_MINOR 10
#define NL_VERSION_MINOR 11
/// \brief Version - Patch level.
///
#define NL_VERSION_PATCHLEVEL 0

View File

@ -237,10 +237,10 @@ void parser_t::frontier()
pstring attachat = get_identifier();
require_token(m_tok_comma);
auto tok = get_token();
nl_fptype r_IN = eval_param(tok);
auto r_IN = stringify_expression(tok);
require_token(tok, m_tok_comma);
tok = get_token();
nl_fptype r_OUT = eval_param(tok);
auto r_OUT = stringify_expression(tok);
require_token(tok, m_tok_paren_right);
m_setup.register_frontier(attachat, r_IN, r_OUT);
@ -341,7 +341,7 @@ void parser_t::netdev_param()
}
else
{
nl_fptype val = eval_param(tok);
auto val = stringify_expression(tok);
m_setup.log().debug("Parser: Param: {1} {2}\n", param, val);
m_setup.register_param(param, val);
require_token(tok, m_tok_paren_right);
@ -354,7 +354,7 @@ void parser_t::netdev_hint()
pstring dev(get_identifier());
require_token(m_tok_comma);
pstring hint(get_identifier());
m_setup.register_param(dev + ".HINT_" + hint, 1);
m_setup.register_param_val(dev + ".HINT_" + hint, 1);
require_token(m_tok_paren_right);
}
@ -379,13 +379,8 @@ void parser_t::device(const pstring &dev_type)
}
else
{
// FIXME: Do we really need this?
nl_fptype value = eval_param(tok);
if (plib::abs(value - plib::floor(value)) > nlconst::magic(1e-30)
|| plib::abs(value) > nlconst::magic(1e9))
params.push_back(plib::pfmt("{1:.9}").e(value));
else
params.push_back(plib::pfmt("{1}")(static_cast<long>(value)));
auto value = stringify_expression(tok);
params.push_back(value);
}
}
@ -398,9 +393,8 @@ void parser_t::device(const pstring &dev_type)
// private
// ----------------------------------------------------------------------------------------
nl_fptype parser_t::eval_param(token_t &tok)
pstring parser_t::stringify_expression(token_t &tok)
{
#if USE_EVAL
int pc(0);
pstring ret;
while (!tok.is(m_tok_comma))
@ -416,45 +410,7 @@ nl_fptype parser_t::eval_param(token_t &tok)
ret += tok.str();
tok = get_token();
}
// FIXME: Not necessary here, should be done if parameter is read by devices
plib::pfunction<nl_fptype> func;
func.compile_infix(ret, {});
return func.evaluate();
#else
static std::array<pstring, 7> macs = {"", "RES_R", "RES_K", "RES_M", "CAP_U", "CAP_N", "CAP_P"};
static std::array<nl_fptype, 7> facs = {
nlconst::magic(1.0),
nlconst::magic(1.0),
nlconst::magic(1e3),
nlconst::magic(1e6),
nlconst::magic(1e-6),
nlconst::magic(1e-9),
nlconst::magic(1e-12)
};
std::size_t f=0;
nl_fptype ret(0);
for (std::size_t i=1; i<macs.size();i++)
if (tok.str() == macs[i])
f = i;
if (f>0)
{
require_token(m_tok_paren_left);
ret = static_cast<nl_fptype>(get_number_double());
require_token(m_tok_paren_right);
}
else
{
bool err(false);
ret = plib::pstonum_ne<nl_fptype>(tok.str(), err);
if (err)
error(MF_PARAM_NOT_FP_1(tok.str()));
}
tok = get_token();
return ret * facs[f];
#endif
return ret;
}
} // namespace netlist

View File

@ -43,9 +43,7 @@ namespace netlist
void verror(const pstring &msg) override;
private:
nl_fptype eval_param(token_t &tok);
pstring stringify_expression(token_t &tok);
token_id_t m_tok_paren_left;
token_id_t m_tok_paren_right;
token_id_t m_tok_comma;

View File

@ -121,11 +121,9 @@ namespace netlist
pstring paramfq = name + "." + tp;
log().debug("Defparam: {1}\n", paramfq);
// remove quotes
if (plib::startsWith(*ptok, "\"") && plib::endsWith(*ptok, "\""))
register_param(paramfq, ptok->substr(1, ptok->length() - 2));
else
register_param(paramfq, *ptok);
register_param(paramfq, *ptok);
++ptok;
}
}
@ -216,11 +214,16 @@ namespace netlist
void nlparse_t::register_param(const pstring &param, const pstring &value)
{
pstring fqn = build_fqn(param);
pstring val(value);
// strip " from stringified strings
if (plib::startsWith(value, "\"") && plib::endsWith(value, "\""))
val = value.substr(1, value.length() - 2);
auto idx = m_param_values.find(fqn);
if (idx == m_param_values.end())
{
if (!m_param_values.insert({fqn, value}).second)
if (!m_param_values.insert({fqn, val}).second)
{
log().fatal(MF_ADDING_PARAMETER_1_TO_PARAMETER_LIST(param));
throw nl_exception(MF_ADDING_PARAMETER_1_TO_PARAMETER_LIST(param));
@ -229,8 +232,8 @@ namespace netlist
else
{
log().warning(MW_OVERWRITING_PARAM_1_OLD_2_NEW_3(fqn, idx->second,
value));
m_param_values[fqn] = value;
val));
m_param_values[fqn] = val;
}
}
@ -239,7 +242,7 @@ namespace netlist
m_factory.register_device(plib::make_unique<factory::library_element_t>(name, name, "", sourcefile));
}
void nlparse_t::register_frontier(const pstring &attach, const nl_fptype r_IN, const nl_fptype r_OUT)
void nlparse_t::register_frontier(const pstring &attach, const pstring &r_IN, const pstring &r_OUT)
{
pstring frontier_name = plib::pfmt("frontier_{1}")(m_frontier_cnt);
m_frontier_cnt++;

View File

@ -53,10 +53,10 @@
setup.register_link_arr( # term1 ", " # __VA_ARGS__);
#define PARAM(name, val) \
setup.register_param(# name, val);
setup.register_param(# name, # val);
#define HINT(name, val) \
setup.register_param(# name ".HINT_" # val, 1);
setup.register_param(# name ".HINT_" # val, "1");
#define NETDEV_PARAMI(name, param, val) \
setup.register_param(# name "." # param, val);
@ -88,7 +88,7 @@ void NETLIST_NAME(name)(netlist::nlparse_t &setup) \
setup.namespace_pop();
#define OPTIMIZE_FRONTIER(attach, r_in, r_out) \
setup.register_frontier(# attach, r_in, r_out);
setup.register_frontier(# attach, PSTRINGIFY_VA(r_in), PSTRINGIFY_VA(r_out));
// -----------------------------------------------------------------------------
// truthtable defines
@ -261,7 +261,7 @@ namespace netlist
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value || std::is_integral<T>::value>::type
register_param(const pstring &param, T value)
register_param_val(const pstring &param, T value)
{
register_param_x(param, static_cast<nl_fptype>(value));
}
@ -274,7 +274,7 @@ namespace netlist
#endif
void register_lib_entry(const pstring &name, const pstring &sourcefile);
void register_frontier(const pstring &attach, nl_fptype r_IN, nl_fptype r_OUT);
void register_frontier(const pstring &attach, const pstring &r_IN, const pstring &r_OUT);
// register a source
void register_source(plib::unique_ptr<plib::psource_t> &&src)

View File

@ -226,7 +226,6 @@ namespace plib {
{
pstring s(STR);
pi++;
// FIXME : \"
while (pi < tmp.size() && tmp[pi] != STR)
{
s += tmp[pi];
@ -454,7 +453,6 @@ namespace plib {
line = process_comments(m_line);
pstring lt = plib::trim(plib::replace_all(line, "\t", " "));
// FIXME ... revise and extend macro handling
if (plib::startsWith(lt, "#"))
{
string_list lti(psplit(lt, " ", true));
@ -462,7 +460,6 @@ namespace plib {
{
m_if_level++;
lt = replace_macros(lt);
//std::vector<pstring> t(psplit(replace_all(lt.substr(3), " ", ""), m_expr_sep));
auto t(simple_iter<ppreprocessor>(this, tokenize(lt.substr(3), m_expr_sep, true, true)));
auto val = static_cast<int>(prepro_expr(t, 255));
t.skip_ws();