mirror of
https://github.com/holub/mame
synced 2025-04-16 05:24:54 +03:00
Netlist lint, first version of a FAQ and small code changes. (#9684)
- Added a first version of a FAQ. - Use better error messages in pfunction. - Made member functions static where appropriate in nld_solver.
This commit is contained in:
parent
0818eafc2f
commit
d20a1982da
151
src/lib/netlist/FAQ.md
Normal file
151
src/lib/netlist/FAQ.md
Normal file
@ -0,0 +1,151 @@
|
||||
# The netlist FAQ
|
||||
|
||||
## Glossary
|
||||
|
||||
BTANB: Bugs That Aren't Bugs. Bugs in the hardware (or software) that are
|
||||
faithfully emulated, therefore not a bug in the emulator.
|
||||
|
||||
## General
|
||||
|
||||
### Have you considered maybe supporting part randomization in the netlist core?
|
||||
|
||||
Yes I did. And decided against it. Which features? Forced randomness - will this
|
||||
be different at every restart? And it would require another parameter per device
|
||||
(specification, e.g. for resistors 5%, 10%, 20%). This would cause more cache
|
||||
usage.
|
||||
|
||||
And I am convinced we would see more BTANBs.
|
||||
|
||||
### How do frontiers work?
|
||||
|
||||
Frontiers divides a netlist into sub netlists, i.e. a number of smaller netlists.
|
||||
Frontiers work best if you have a low impedance to high impedance transition.
|
||||
This is best illustrated by an example. Consider the following mixing stage
|
||||
|
||||
R1
|
||||
S1 >-----1RRRR2---------+
|
||||
|
|
||||
R2 |
|
||||
S2 >-----1RRRR2---------+----------> Out
|
||||
|
|
||||
R
|
||||
R3 R
|
||||
R
|
||||
|
|
||||
GND
|
||||
|
||||
With `OPTIMIZE_FRONTIER(R2.2, R3, R2)` this becomes:
|
||||
|
||||
R1
|
||||
S1 >-----1RRRR2--------------------------------+
|
||||
|
|
||||
########################## |
|
||||
R2 # R2 # |
|
||||
S2 >-----1RRRR2-----+-->AnIn AnOut>--RRRR------+----------> Out
|
||||
# | # |
|
||||
# R # R
|
||||
# R R3 # R3 R
|
||||
# R # R
|
||||
# | # |
|
||||
# GND Frontier # GND
|
||||
# #
|
||||
##########################
|
||||
|
||||
As a result, provided there are no other connections between the parts
|
||||
generating S1 and S2 the "S2 part" will now have a separate solver.
|
||||
|
||||
The size (aka number of nets) of the solver for S1 will be smaller.
|
||||
The size of the solver for S2 and the rest of the circuit will be smaller
|
||||
as well.
|
||||
|
||||
Frontiers assume that there is little to no feedback from the "out" terminal to the "in"
|
||||
terminal. This is a safe assumption if the "in" terminal e.g. is connected to an
|
||||
op-amp output (typically < 500 Ohm) and R2 in the example above is in the 10 KOhm range.
|
||||
|
||||
## MAME specific
|
||||
|
||||
### Is there an example of a netlist that takes input from an AY-8910/2 and handles it?
|
||||
|
||||
There are quite a few:
|
||||
|
||||
- nl_kidniki.cpp
|
||||
- nl_konami.cpp
|
||||
- 1942.cpp
|
||||
|
||||
Basically the AY8910 driver has to be configured to push resistor values to the
|
||||
input stream. The konami drivers (scramble, frogger and friends) do that and
|
||||
should be used as a reference. 1942 connects outputs and may be an even better example.
|
||||
|
||||
## Models
|
||||
|
||||
### Is there are JFET model?
|
||||
|
||||
No, there is currently no JFET model in netlist. They are close to depletion
|
||||
mode MOSFETs with very low gate capacitance so you may try a generic n-mosfet
|
||||
with a negative trigger voltage. Example:
|
||||
|
||||
MOSFET(Q21, "NMOS(VTO=-1.0)")
|
||||
|
||||
Writing an analog model is a very time-consuming task. The simplified model above should
|
||||
deliver reasonable results.
|
||||
|
||||
## Operational Amplifiers
|
||||
|
||||
### What's UGF? Would like to understand this black magic a little better. :)
|
||||
|
||||
UGF = Unity Gain Frequency, usually identical to gain-bandwidth product for
|
||||
op-amps. The idea is that the an op-amp's open-loop gain (its amplification
|
||||
factor when used without any negative feedback) is proportional to the
|
||||
frequency of its input signal. For slowly-varying, near-DC signals, this gain
|
||||
will be extremely high (in this case, a gain of 10000 at 1 Hz), which is part
|
||||
of what makes an op-amp effective. In practice the op-amp's actual gain will
|
||||
be limited by whatever negative feedback is applied, but its open-loop gain
|
||||
is a key quantity in computing its actual response. Because the op-amp is
|
||||
limited in how fast it can respond to its input, its open-loop gain will
|
||||
drop as the frequency of the input signal rises, eventually falling to a
|
||||
gain of 1 (output = input) at the unity gain frequency. In this case
|
||||
couriersud set the unity gain frequency is 10 kHz, which is much lower than
|
||||
reality, in order to make the op-amp response in the oscillators slower and
|
||||
easier for the netlist solver to handle without using very small time steps.
|
||||
According to Texas Instruments, the TL084's actual gain-bandwidth product
|
||||
(remember, this is the same as the UGF) is typically 3 MHz.
|
||||
|
||||
## Documentation
|
||||
|
||||
### What is the preferred documentation format?
|
||||
|
||||
The preferred documentation for devices is to use the netlist documentation format.
|
||||
This will ensure that the devices are properly documented in the Doxygen
|
||||
documentation created by `make doc`
|
||||
|
||||
An example entry is given here:
|
||||
|
||||
//- Identifier: SN74LS629_DIP
|
||||
//- Title: SN74LS629 VOLTAGE-CONTROLLED OSCILLATORS
|
||||
//- Description: Please add a detailed description
|
||||
//- FIXME: Missing description
|
||||
//-
|
||||
//- Pinalias: 2FC,1FC,1RNG,1CX1,1CX2,1ENQ,1Y,OSC_GND,GND,2Y,2ENQ,2CX2,2CX1,2RNG,OSC_VCC,VCC
|
||||
//- Package: DIP
|
||||
//- Param: A.CAP
|
||||
//- Capacitor value of capacitor connected to 1CX1 and 1CX2 pins
|
||||
//- Param: B.CAP
|
||||
//- Capacitor value of capacitor connected to 2CX1 and 2CX2 pins
|
||||
//- Limitations:
|
||||
//- The capacitor inputs are NC. Capacitor values need to be specified as
|
||||
//- ```
|
||||
//- SN74LS629_DIP(X)
|
||||
//- PARAM(X.A.CAP, CAP_U(1))
|
||||
//- PARAM(X.B.CAP, CAP_U(2))
|
||||
//- ```
|
||||
//-
|
||||
//- Example: 74ls629.cpp,74ls629_example
|
||||
//-
|
||||
//- FunctionTable:
|
||||
//- http://pdf.datasheetcatalog.com/datasheets/400/335051_DS.pdf
|
||||
//-
|
||||
static NETLIST_START(SN74LS629_DIP)
|
||||
|
||||
If you add an example in the examples folder this will be included in the
|
||||
documentation as well.
|
||||
|
@ -39,7 +39,7 @@ namespace netlist::devices {
|
||||
private:
|
||||
NETLIB_HANDLERI(in)
|
||||
{
|
||||
m_enable = m_E() ? false : true;
|
||||
m_enable = m_E() ? false : true; // NOLINT
|
||||
m_o = (m_A[1]() << 1) | m_A[0]();
|
||||
for (std::size_t i=0; i<4; i++)
|
||||
m_D[i].push((i == m_o && m_enable) ? 0 : 1, NLTIME_FROM_NS(21));
|
||||
@ -47,7 +47,7 @@ namespace netlist::devices {
|
||||
|
||||
NETLIB_HANDLERI(e)
|
||||
{
|
||||
m_enable = m_E() ? false : true;
|
||||
m_enable = m_E() ? false : true; // NOLINT
|
||||
m_o = (m_A[1]() << 1) | m_A[0]();
|
||||
for (std::size_t i=0; i<4; i++)
|
||||
m_D[i].push((i == m_o && m_enable) ? 0 : 1, NLTIME_FROM_NS(18));
|
||||
|
@ -17,6 +17,13 @@
|
||||
|
||||
namespace plib {
|
||||
|
||||
PERRMSGV(MF_FUNCTION_UNKNOWN_TOKEN, 2, "pfunction: unknown/misformatted token <{1}> in <{2}>")
|
||||
PERRMSGV(MF_FUNCTION_STACK_UNDERFLOW, 2, "pfunction: stack underflow on token <{1}> in <{2}>")
|
||||
PERRMSGV(MF_FUNCTION_STACK_OVERFLOW, 2, "pfunction: stack overflow on token <{1}> in <{2}>")
|
||||
PERRMSGV(MF_FUNCTION_PARENTHESIS_INEQUALITY, 2, "pfunction: parenthesis inequality on token <{1}> in <{2}>")
|
||||
PERRMSGV(MF_FUNCTION_STACK_UNEQUAL_ONE, 2, "pfunction: stack count {1} different to one on <{2}>")
|
||||
PERRMSGV(MF_FUNCTION_STACK_UNDERFLOW_INFIX, 1, "pfunction: stack underflow during infix parsing of: <{1}>")
|
||||
|
||||
static constexpr const std::size_t MAX_STACK = 32;
|
||||
|
||||
struct pcmd_t
|
||||
@ -141,20 +148,20 @@ namespace plib {
|
||||
else
|
||||
rc = rpn_inst(plib::pstonum_ne<NT>(plib::left(cmd, cmd.length()-1), err) * r->second);
|
||||
if (err)
|
||||
throw pexception(plib::pfmt("pfunction: unknown/misformatted token <{1}> in <{2}>")(cmd)(expr));
|
||||
throw pexception(MF_FUNCTION_UNKNOWN_TOKEN(cmd, expr));
|
||||
stk += 1;
|
||||
}
|
||||
}
|
||||
if (stk < 1)
|
||||
throw pexception(plib::pfmt("pfunction: stack underflow on token <{1}> in <{2}>")(cmd)(expr));
|
||||
throw pexception(MF_FUNCTION_STACK_UNDERFLOW(cmd, expr));
|
||||
if (stk >= narrow_cast<int>(MAX_STACK))
|
||||
throw pexception(plib::pfmt("pfunction: stack overflow on token <{1}> in <{2}>")(cmd)(expr));
|
||||
throw pexception(MF_FUNCTION_STACK_OVERFLOW(cmd, expr));
|
||||
if (rc.cmd() == LP || rc.cmd() == RP)
|
||||
throw pexception(plib::pfmt("pfunction: parenthesis inequality on token <{1}> in <{2}>")(cmd)(expr));
|
||||
throw pexception(MF_FUNCTION_PARENTHESIS_INEQUALITY(cmd, expr));
|
||||
m_precompiled.push_back(rc);
|
||||
}
|
||||
if (stk != 1)
|
||||
throw pexception(plib::pfmt("pfunction: stack count {1} different to one on <{2}>")(stk, expr));
|
||||
throw pexception(MF_FUNCTION_STACK_UNEQUAL_ONE(stk, expr));
|
||||
compress();
|
||||
}
|
||||
|
||||
@ -187,7 +194,7 @@ namespace plib {
|
||||
static pstring pop_check(std::stack<pstring> &stk, const pstring &expr) noexcept(false)
|
||||
{
|
||||
if (stk.empty())
|
||||
throw pexception(plib::pfmt("pfunction: stack underflow during infix parsing of: <{1}>")(expr));
|
||||
throw pexception(MF_FUNCTION_STACK_UNDERFLOW_INFIX(expr));
|
||||
pstring res = stk.top();
|
||||
stk.pop();
|
||||
return res;
|
||||
|
@ -13,7 +13,7 @@ namespace plib {
|
||||
PERRMSGV(MF_EXPECTED_IDENTIFIER_GOT_1, 1, "Expected an identifier, got <{1}>")
|
||||
PERRMSGV(MF_EXPECTED_ID_OR_NUM_GOT_1, 1, "Expected an identifier or number, got <{1}>")
|
||||
PERRMSGV(MF_EXPECTED_NUMBER_GOT_1, 1, "Expected a number, got <{1}>")
|
||||
PERRMSGV(MF_EXPECTED_LONGINT_GOT_1, 1, "Expected a logn int, got <{1}>")
|
||||
PERRMSGV(MF_EXPECTED_LONGINT_GOT_1, 1, "Expected a long int, got <{1}>")
|
||||
PERRMSGV(MF_EXPECTED_LINENUM_GOT_1, 1, "Expected line number after line marker but got <{1}>")
|
||||
PERRMSGV(MF_EXPECTED_FILENAME_GOT_1, 1, "Expected file name after line marker but got <{1}>")
|
||||
|
||||
|
@ -64,35 +64,35 @@ namespace solver
|
||||
|
||||
struct solver_parameter_defaults
|
||||
{
|
||||
constexpr nl_fptype m_freq() { return nlconst::magic(48000.0); }
|
||||
static constexpr nl_fptype m_freq() { return nlconst::magic(48000.0); }
|
||||
|
||||
// iteration parameters
|
||||
constexpr nl_fptype m_gs_sor() { return nlconst::magic(1.059); }
|
||||
constexpr matrix_type_e m_method() { return matrix_type_e::MAT_CR; }
|
||||
constexpr matrix_fp_type_e m_fp_type() { return matrix_fp_type_e::DOUBLE; }
|
||||
constexpr nl_fptype m_reltol() { return nlconst::magic(1e-3); }
|
||||
constexpr nl_fptype m_vntol() { return nlconst::magic(1e-7); }
|
||||
constexpr nl_fptype m_accuracy() { return nlconst::magic(1e-7); }
|
||||
constexpr std::size_t m_nr_loops() { return 250; }
|
||||
constexpr std::size_t m_gs_loops() { return 50; }
|
||||
static constexpr nl_fptype m_gs_sor() { return nlconst::magic(1.059); }
|
||||
static constexpr matrix_type_e m_method() { return matrix_type_e::MAT_CR; }
|
||||
static constexpr matrix_fp_type_e m_fp_type() { return matrix_fp_type_e::DOUBLE; }
|
||||
static constexpr nl_fptype m_reltol() { return nlconst::magic(1e-3); }
|
||||
static constexpr nl_fptype m_vntol() { return nlconst::magic(1e-7); }
|
||||
static constexpr nl_fptype m_accuracy() { return nlconst::magic(1e-7); }
|
||||
static constexpr std::size_t m_nr_loops() { return 250; }
|
||||
static constexpr std::size_t m_gs_loops() { return 50; }
|
||||
|
||||
// general parameters
|
||||
constexpr nl_fptype m_gmin() { return nlconst::magic(1e-9); }
|
||||
constexpr bool m_pivot() { return false; }
|
||||
constexpr nl_fptype m_nr_recalc_delay(){ return netlist_time::quantum().as_fp<nl_fptype>(); }
|
||||
constexpr int m_parallel() { return 0; }
|
||||
static constexpr nl_fptype m_gmin() { return nlconst::magic(1e-9); }
|
||||
static constexpr bool m_pivot() { return false; }
|
||||
static constexpr nl_fptype m_nr_recalc_delay(){ return netlist_time::quantum().as_fp<nl_fptype>(); }
|
||||
static constexpr int m_parallel() { return 0; }
|
||||
|
||||
constexpr nl_fptype m_min_ts_ts() { return nlconst::magic(1e-9); }
|
||||
static constexpr nl_fptype m_min_ts_ts() { return nlconst::magic(1e-9); }
|
||||
// automatic time step
|
||||
constexpr bool m_dynamic_ts() { return false; }
|
||||
constexpr nl_fptype m_dynamic_lte() { return nlconst::magic(1e-5); }
|
||||
constexpr nl_fptype m_dynamic_min_ts() { return nlconst::magic(1e-6); }
|
||||
static constexpr bool m_dynamic_ts() { return false; }
|
||||
static constexpr nl_fptype m_dynamic_lte() { return nlconst::magic(1e-5); }
|
||||
static constexpr nl_fptype m_dynamic_min_ts() { return nlconst::magic(1e-6); }
|
||||
|
||||
// matrix sorting
|
||||
constexpr matrix_sort_type_e m_sort_type() { return matrix_sort_type_e::PREFER_IDENTITY_TOP_LEFT; }
|
||||
static constexpr matrix_sort_type_e m_sort_type() { return matrix_sort_type_e::PREFER_IDENTITY_TOP_LEFT; }
|
||||
|
||||
// special
|
||||
constexpr bool m_use_gabs() { return true; }
|
||||
static constexpr bool m_use_gabs() { return true; }
|
||||
|
||||
static solver_parameter_defaults &get_instance()
|
||||
{
|
||||
|
@ -328,7 +328,7 @@ namespace solver
|
||||
}
|
||||
m_cnt++;
|
||||
|
||||
if (false)
|
||||
if (false) // NOLINT
|
||||
for (unsigned i=0; i<iN; i++)
|
||||
{
|
||||
float_type tmp = plib::constants<FT>::zero();
|
||||
|
@ -362,6 +362,7 @@ namespace devices
|
||||
auto &pt = dynamic_cast<terminal_t &>(*term);
|
||||
// check the connected terminal
|
||||
const auto *const connected_terminals = nlstate.setup().get_connected_terminals(pt);
|
||||
// NOLINTNEXTLINE proposal does not work for VS
|
||||
for (auto ct = connected_terminals->begin(); *ct != nullptr; ct++)
|
||||
{
|
||||
analog_net_t &connected_net = (*ct)->net();
|
||||
|
Loading…
Reference in New Issue
Block a user