mirror of
https://github.com/holub/mame
synced 2025-10-04 16:34:53 +03:00
netlist: MB3614 again, function controlled VARCLOCK and other
improvements. - fix MB3614 parameter - Added VARCLOCK which derives step size from function - optimized function handling in CS and VS - fixed a bug in ppreprocessor - add trunc to pfunction - added opamp_amplification_curve to derive characteristic amplification curve
This commit is contained in:
parent
140dc2237e
commit
58e6383ada
@ -32,7 +32,7 @@ NETLIST_START(cmos_inverter_clk)
|
||||
//CLOCK(V, 500000)
|
||||
#else
|
||||
VS(V, 5)
|
||||
PARAM(V.FUNC, "T 5e6 *")
|
||||
PARAM(V.FUNC, "T * 5e6")
|
||||
#endif
|
||||
|
||||
MOSFET(P, "PMOS(VTO=-0.5 GAMMA=0.5 TOX=20n)")
|
||||
|
@ -111,11 +111,11 @@ NETLIST_START(dummy)
|
||||
NET_C(RX1.2, XU16.7)
|
||||
#endif
|
||||
|
||||
/* The opamp actually has an FPF of about 200k. This doesn't work here and causes oscillations.
|
||||
/* The opamp actually has an FPF of about 1000k. This doesn't work here and causes oscillations.
|
||||
* FPF here therefore about half the Solver clock.
|
||||
*/
|
||||
PARAM(XU16.B.MODEL, "MB3614(TYPE=3 UGF=22k)")
|
||||
PARAM(XU17.C.MODEL, "MB3614(TYPE=3 UGF=22k)")
|
||||
PARAM(XU16.B.MODEL, "MB3614(TYPE=3)")
|
||||
PARAM(XU17.C.MODEL, "MB3614(TYPE=3 UGF=44k)")
|
||||
#if 0
|
||||
PARAM(XU17.A.MODEL, "MB3614(TYPE=1)")
|
||||
PARAM(XU17.B.MODEL, "MB3614(TYPE=1)")
|
||||
|
72
nl_examples/opamp_amplification_curve.cpp
Normal file
72
nl_examples/opamp_amplification_curve.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
// license:GPL-2.0+
|
||||
// copyright-holders:Couriersud
|
||||
/*
|
||||
* Script to analyze opamp amplification as a function of frequency.
|
||||
*
|
||||
* ./nltool -t 0.5 -f nl_examples/opamp_amplification_curve.cpp
|
||||
*
|
||||
* t=0.0: 10 Hz
|
||||
* t=0.1: 100 Hz
|
||||
* t=0.2: 1000 Hz
|
||||
* t=0.3: 10000 Hz
|
||||
* t=0.4: 100000 Hz
|
||||
* ....
|
||||
*
|
||||
* ./plot_nl.sh --log Y Z
|
||||
*/
|
||||
|
||||
|
||||
#include "netlist/devices/net_lib.h"
|
||||
|
||||
#define OPAMP_TEST "MB3614(FPF=10 UGF=1000k)"
|
||||
|
||||
NETLIST_START(main)
|
||||
|
||||
/* Standard stuff */
|
||||
|
||||
//VARCLOCK(clk, "0.5 / pow(10, 1 + T * 4)")
|
||||
//CLOCK(clk, 1000)
|
||||
SOLVER(Solver, 48000)
|
||||
PARAM(Solver.ACCURACY, 1e-7)
|
||||
PARAM(Solver.NR_LOOPS, 300)
|
||||
PARAM(Solver.DYNAMIC_TS, 1)
|
||||
PARAM(Solver.DYNAMIC_MIN_TIMESTEP, 1e-7)
|
||||
|
||||
VS(vs, 0)
|
||||
PARAM(vs.FUNC, "0.001 * sin(6.28 * pow(10, 1 + 10*T) * T)")
|
||||
//PARAM(vs.FUNC, "0.001 * sin(6.28 * pow(10, trunc((1 + T * 4)*2)/2) * T)")
|
||||
//PARAM(vs.FUNC, "1.001 * sin(6.28 * 100 * T)")
|
||||
PARAM(vs.R, 0.001)
|
||||
ALIAS(clk, vs.1)
|
||||
NET_C(vs.2, GND)
|
||||
ANALOG_INPUT(V12, 12)
|
||||
ANALOG_INPUT(VM12, -12)
|
||||
|
||||
OPAMP(op,OPAMP_TEST)
|
||||
|
||||
NET_C(op.GND, VM12)
|
||||
NET_C(op.VCC, V12)
|
||||
|
||||
/* Opamp B wired as inverting amplifier connected to output of first opamp */
|
||||
|
||||
RES(R1, 0.1)
|
||||
RES(R2, 10000)
|
||||
|
||||
NET_C(op.PLUS, GND)
|
||||
NET_C(op.MINUS, R2.2)
|
||||
NET_C(op.MINUS, R1.2)
|
||||
|
||||
NET_C(clk, R1.1)
|
||||
NET_C(op.OUT, R2.1)
|
||||
|
||||
RES(RL, 2000)
|
||||
NET_C(RL.2, GND)
|
||||
NET_C(RL.1, op.OUT)
|
||||
|
||||
AFUNC(f, 1, "A0 * 1000")
|
||||
NET_C(f.A0, op.OUT)
|
||||
#if 1
|
||||
LOG(log_Y, R1.1)
|
||||
LOG(log_Z, f)
|
||||
#endif
|
||||
NETLIST_END()
|
@ -223,18 +223,14 @@ namespace netlist
|
||||
m_EBUF->reset();
|
||||
m_CP->reset();
|
||||
m_RP.reset();
|
||||
#if 0
|
||||
double CP = 0.0;
|
||||
double RP = 1000;
|
||||
double G = m_model.m_UGF / m_model.m_FPF / RP;
|
||||
#else
|
||||
|
||||
double CP = m_model.m_DAB / m_model.m_SLEW;
|
||||
double RP = 0.5 / constants::pi() / CP / m_model.m_FPF;
|
||||
double G = m_model.m_UGF / m_model.m_FPF / RP;
|
||||
#endif
|
||||
printf("OPAMP %s: %g %g %g\n", name().c_str(), CP, RP, G);
|
||||
|
||||
//printf("OPAMP %s: %g %g %g\n", name().c_str(), CP, RP, G);
|
||||
if (m_model.m_SLEW / (4.0 * constants::pi() * 0.0258) < m_model.m_UGF)
|
||||
printf("failed!\n");
|
||||
log().warning("Opamp <{1}> parameters fail convergence criteria", this->name());
|
||||
|
||||
m_CP->m_C.setTo(CP);
|
||||
m_RP.set_R(RP);
|
||||
|
@ -399,11 +399,12 @@ namespace analog
|
||||
, m_V(*this, "V", 0.0)
|
||||
, m_func(*this,"FUNC", "")
|
||||
, m_compiled(this->name() + ".FUNCC", this, this->state().run_state_manager())
|
||||
, m_funcparam({0.0})
|
||||
{
|
||||
register_subalias("P", m_P);
|
||||
register_subalias("N", m_N);
|
||||
if (m_func() != "")
|
||||
m_compiled.compile_postfix(std::vector<pstring>({{"T"}}), m_func());
|
||||
m_compiled.compile(std::vector<pstring>({{"T"}}), m_func());
|
||||
}
|
||||
|
||||
NETLIB_IS_TIMESTEP(m_func() != "")
|
||||
@ -411,8 +412,9 @@ namespace analog
|
||||
NETLIB_TIMESTEPI()
|
||||
{
|
||||
m_t += step;
|
||||
m_funcparam[0] = m_t;
|
||||
this->set_G_V_I(1.0 / m_R(),
|
||||
m_compiled.evaluate(std::vector<double>({m_t})),
|
||||
m_compiled.evaluate(m_funcparam),
|
||||
0.0);
|
||||
}
|
||||
|
||||
@ -431,6 +433,7 @@ namespace analog
|
||||
param_double_t m_V;
|
||||
param_str_t m_func;
|
||||
plib::pfunction m_compiled;
|
||||
std::vector<double> m_funcparam;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -445,18 +448,20 @@ namespace analog
|
||||
, m_I(*this, "I", 1.0)
|
||||
, m_func(*this,"FUNC", "")
|
||||
, m_compiled(this->name() + ".FUNCC", this, this->state().run_state_manager())
|
||||
, m_funcparam({0.0})
|
||||
{
|
||||
register_subalias("P", m_P);
|
||||
register_subalias("N", m_N);
|
||||
if (m_func() != "")
|
||||
m_compiled.compile_postfix(std::vector<pstring>({{"T"}}), m_func());
|
||||
m_compiled.compile(std::vector<pstring>({{"T"}}), m_func());
|
||||
}
|
||||
|
||||
NETLIB_IS_TIMESTEP(m_func() != "")
|
||||
NETLIB_TIMESTEPI()
|
||||
{
|
||||
m_t += step;
|
||||
const double I = m_compiled.evaluate(std::vector<double>({m_t}));
|
||||
m_funcparam[0] = m_t;
|
||||
const double I = m_compiled.evaluate(m_funcparam);
|
||||
set_mat(0.0, 0.0, -I,
|
||||
0.0, 0.0, I);
|
||||
}
|
||||
@ -476,6 +481,7 @@ namespace analog
|
||||
param_double_t m_I;
|
||||
param_str_t m_func;
|
||||
plib::pfunction m_compiled;
|
||||
std::vector<double> m_funcparam;
|
||||
};
|
||||
|
||||
|
||||
|
@ -52,6 +52,7 @@ namespace devices
|
||||
LIB_ENTRY(log)
|
||||
LIB_ENTRY(logD)
|
||||
LIB_ENTRY(clock)
|
||||
LIB_ENTRY(varclock)
|
||||
LIB_ENTRY(extclock)
|
||||
LIB_ENTRY(mainclock)
|
||||
LIB_ENTRY(gnd)
|
||||
|
@ -18,20 +18,6 @@ namespace netlist
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// clock
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
NETLIB_UPDATE_PARAM(clock)
|
||||
{
|
||||
m_inc = netlist_time::from_double(1.0 / (m_freq() * 2.0));
|
||||
}
|
||||
|
||||
NETLIB_UPDATE(clock)
|
||||
{
|
||||
m_Q.push(!m_feedback(), m_inc);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// extclock
|
||||
// ----------------------------------------------------------------------------------------
|
||||
@ -123,6 +109,7 @@ namespace netlist
|
||||
NETLIB_DEVICE_IMPL(function, "AFUNC", "N,FUNC")
|
||||
NETLIB_DEVICE_IMPL(analog_input, "ANALOG_INPUT", "IN")
|
||||
NETLIB_DEVICE_IMPL(clock, "CLOCK", "FREQ")
|
||||
NETLIB_DEVICE_IMPL(varclock, "VARCLOCK", "FUNC")
|
||||
NETLIB_DEVICE_IMPL(extclock, "EXTCLOCK", "FREQ,PATTERN")
|
||||
NETLIB_DEVICE_IMPL(res_sw, "RES_SWITCH", "+IN,+P1,+P2")
|
||||
NETLIB_DEVICE_IMPL(mainclock, "MAINCLOCK", "FREQ")
|
||||
|
@ -36,6 +36,10 @@
|
||||
NET_REGISTER_DEV(CLOCK, name) \
|
||||
PARAM(name.FREQ, freq)
|
||||
|
||||
#define VARCLOCK(name, func) \
|
||||
NET_REGISTER_DEV(VARCLOCK, name) \
|
||||
PARAM(name.FUNC, func)
|
||||
|
||||
#define EXTCLOCK(name, freq, pattern) \
|
||||
NET_REGISTER_DEV(EXTCLOCK, name) \
|
||||
PARAM(name.FREQ, freq) \
|
||||
|
@ -94,9 +94,17 @@ namespace netlist
|
||||
|
||||
connect(m_feedback, m_Q);
|
||||
}
|
||||
NETLIB_UPDATEI();
|
||||
//NETLIB_RESETI();
|
||||
NETLIB_UPDATE_PARAMI();
|
||||
|
||||
NETLIB_UPDATE_PARAMI()
|
||||
{
|
||||
m_inc = netlist_time::from_double(1.0 / (m_freq() * 2.0));
|
||||
}
|
||||
|
||||
NETLIB_UPDATEI()
|
||||
{
|
||||
m_Q.push(!m_feedback(), m_inc);
|
||||
}
|
||||
|
||||
private:
|
||||
logic_input_t m_feedback;
|
||||
@ -106,6 +114,42 @@ namespace netlist
|
||||
netlist_time m_inc;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// varclock
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
NETLIB_OBJECT(varclock)
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(varclock)
|
||||
, m_feedback(*this, "FB")
|
||||
, m_Q(*this, "Q")
|
||||
, m_func(*this,"FUNC", "")
|
||||
, m_compiled(this->name() + ".FUNCC", this, this->state().run_state_manager())
|
||||
, m_funcparam({0.0})
|
||||
{
|
||||
if (m_func() != "")
|
||||
m_compiled.compile(std::vector<pstring>({{"T"}}), m_func());
|
||||
connect(m_feedback, m_Q);
|
||||
}
|
||||
//NETLIB_RESETI();
|
||||
//NETLIB_UPDATE_PARAMI()
|
||||
|
||||
NETLIB_UPDATEI()
|
||||
{
|
||||
m_funcparam[0] = exec().time().as_double();
|
||||
const netlist_time m_inc = netlist_time::from_double(m_compiled.evaluate(m_funcparam));
|
||||
m_Q.push(!m_feedback(), m_inc);
|
||||
}
|
||||
|
||||
private:
|
||||
logic_input_t m_feedback;
|
||||
logic_output_t m_Q;
|
||||
|
||||
param_str_t m_func;
|
||||
plib::pfunction m_compiled;
|
||||
std::vector<double> m_funcparam;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// extclock
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -225,7 +225,7 @@ NETLIST_START(OPAMP_lib)
|
||||
|
||||
NET_MODEL("LM324 OPAMP(TYPE=3 VLH=2.0 VLL=0.2 FPF=5 UGF=500k SLEW=0.3M RI=1000k RO=50 DAB=0.00075)")
|
||||
NET_MODEL("LM358 OPAMP(TYPE=3 VLH=2.0 VLL=0.2 FPF=5 UGF=500k SLEW=0.3M RI=1000k RO=50 DAB=0.001)")
|
||||
NET_MODEL("MB3614 OPAMP(TYPE=3 VLH=1.4 VLL=0.02 FPF=2 UGF=200k SLEW=0.6M RI=1000k RO=50 DAB=0.002)")
|
||||
NET_MODEL("MB3614 OPAMP(TYPE=3 VLH=1.4 VLL=0.02 FPF=10 UGF=1000k SLEW=0.6M RI=1000k RO=50 DAB=0.002)")
|
||||
NET_MODEL("UA741 OPAMP(TYPE=3 VLH=1.0 VLL=1.0 FPF=5 UGF=1000k SLEW=0.5M RI=2000k RO=75 DAB=0.0017)")
|
||||
NET_MODEL("LM747 OPAMP(TYPE=3 VLH=1.0 VLL=1.0 FPF=5 UGF=1000k SLEW=0.5M RI=2000k RO=50 DAB=0.0017)")
|
||||
NET_MODEL("LM747A OPAMP(TYPE=3 VLH=2.0 VLL=2.0 FPF=5 UGF=1000k SLEW=0.7M RI=6000k RO=50 DAB=0.0015)")
|
||||
|
@ -52,6 +52,8 @@ void pfunction::compile_postfix(const std::vector<pstring> &inputs,
|
||||
{ rc.m_cmd = SIN; stk -= 0; }
|
||||
else if (cmd == "cos")
|
||||
{ rc.m_cmd = COS; stk -= 0; }
|
||||
else if (cmd == "trunc")
|
||||
{ rc.m_cmd = TRUNC; stk -= 0; }
|
||||
else if (cmd == "rand")
|
||||
{ rc.m_cmd = RAND; stk += 1; }
|
||||
else
|
||||
@ -72,16 +74,16 @@ void pfunction::compile_postfix(const std::vector<pstring> &inputs,
|
||||
bool err;
|
||||
rc.m_param = plib::pstonum_ne<decltype(rc.m_param)>(cmd, err);
|
||||
if (err)
|
||||
throw plib::pexception(plib::pfmt("nld_function: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr));
|
||||
throw plib::pexception(plib::pfmt("pfunction: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr));
|
||||
stk += 1;
|
||||
}
|
||||
}
|
||||
if (stk < 1)
|
||||
throw plib::pexception(plib::pfmt("nld_function: stack underflow on token <{1}> in <{2}>")(cmd)(expr));
|
||||
throw plib::pexception(plib::pfmt("pfunction: stack underflow on token <{1}> in <{2}>")(cmd)(expr));
|
||||
m_precompiled.push_back(rc);
|
||||
}
|
||||
if (stk != 1)
|
||||
throw plib::pexception(plib::pfmt("nld_function: stack count different to one on <{2}>")(expr));
|
||||
throw plib::pexception(plib::pfmt("pfunction: stack count different to one on <{2}>")(expr));
|
||||
}
|
||||
|
||||
static int get_prio(const pstring &v)
|
||||
@ -103,7 +105,7 @@ static int get_prio(const pstring &v)
|
||||
static pstring pop_check(std::stack<pstring> &stk, const pstring &expr)
|
||||
{
|
||||
if (stk.size() == 0)
|
||||
throw plib::pexception(plib::pfmt("nld_function: stack underflow during infix parsing of: <{1}>")(expr));
|
||||
throw plib::pexception(plib::pfmt("pfunction: stack underflow during infix parsing of: <{1}>")(expr));
|
||||
pstring res = stk.top();
|
||||
stk.pop();
|
||||
return res;
|
||||
@ -201,6 +203,7 @@ double pfunction::evaluate(const std::vector<double> &values)
|
||||
OP(POW, 1, std::pow(ST2, ST1))
|
||||
OP(SIN, 0, std::sin(ST2))
|
||||
OP(COS, 0, std::cos(ST2))
|
||||
OP(TRUNC, 0, std::trunc(ST2))
|
||||
case RAND:
|
||||
stack[ptr++] = lfsr_random();
|
||||
break;
|
||||
|
@ -34,6 +34,7 @@ namespace plib {
|
||||
SIN,
|
||||
COS,
|
||||
RAND, /* random number between 0 and 1 */
|
||||
TRUNC,
|
||||
PUSH_CONST,
|
||||
PUSH_INPUT
|
||||
};
|
||||
|
@ -282,6 +282,7 @@ ppreprocessor::ppreprocessor(defines_map_type *defines)
|
||||
m_expr_sep.emplace_back("&&");
|
||||
m_expr_sep.emplace_back("||");
|
||||
m_expr_sep.emplace_back("==");
|
||||
m_expr_sep.emplace_back(",");
|
||||
m_expr_sep.emplace_back(" ");
|
||||
m_expr_sep.emplace_back("\t");
|
||||
|
||||
@ -508,9 +509,18 @@ pstring ppreprocessor::process_line(pstring line)
|
||||
{
|
||||
if (m_ifflag == 0)
|
||||
{
|
||||
if (lti.size() != 3)
|
||||
error("PREPRO: only simple defines allowed: " + line);
|
||||
m_defines.insert({lti[1], define_t(lti[1], lti[2])});
|
||||
if (lti.size() < 2)
|
||||
error("PREPRO: define needs at least one argument: " + line);
|
||||
else if (lti.size() == 2)
|
||||
m_defines.insert({lti[1], define_t(lti[1], "")});
|
||||
else
|
||||
{
|
||||
pstring arg("");
|
||||
for (int i=2; i<lti.size() - 1; i++)
|
||||
arg += lti[i] + " ";
|
||||
arg += lti[lti.size()-1];
|
||||
m_defines.insert({lti[1], define_t(lti[1], arg)});
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -241,7 +241,7 @@ NETLIST_END()
|
||||
|
||||
static NETLIST_START(NOISE)
|
||||
CS(FC, 0)
|
||||
PARAM(FC.FUNC, "0.0000001 rand *")
|
||||
PARAM(FC.FUNC, "0.0000001 * rand()")
|
||||
|
||||
ALIAS(E, FC.P)
|
||||
ALIAS(B, FC.N)
|
||||
|
Loading…
Reference in New Issue
Block a user