Fix clang "-Wno-weak-vtables" warnings in netlist source. Refactored

code along the way. (nw)
This commit is contained in:
couriersud 2017-01-05 01:43:12 +01:00
parent 67841056da
commit 02c3f45bff
28 changed files with 1041 additions and 729 deletions

View File

@ -81,6 +81,7 @@ project "netlist"
MAME_DIR .. "src/lib/netlist/analog/nld_opamps.h",
MAME_DIR .. "src/lib/netlist/solver/nld_solver.cpp",
MAME_DIR .. "src/lib/netlist/solver/nld_solver.h",
MAME_DIR .. "src/lib/netlist/solver/nld_matrix_solver.cpp",
MAME_DIR .. "src/lib/netlist/solver/nld_matrix_solver.h",
MAME_DIR .. "src/lib/netlist/solver/nld_ms_direct.h",
MAME_DIR .. "src/lib/netlist/solver/nld_ms_direct1.h",

View File

@ -167,9 +167,9 @@ maketree: $(sort $(OBJDIRS))
.PHONY: clang mingw doc
clang:
$(MAKE) CC=clang++ LD=clang++ CEXTRAFLAGS="-Weverything -Werror -Wno-padded -Wno-weak-vtables -Wno-missing-variable-declarations -Wconversion -Wno-c++98-compat -Wno-float-equal -Wno-cast-align -Wno-global-constructors -Wno-c++98-compat-pedantic -Wno-exit-time-destructors -Wno-format-nonliteral -Wno-weak-template-vtables"
$(MAKE) CC=clang++ LD=clang++ CEXTRAFLAGS="-Weverything -Werror -Wno-padded -Wno-missing-variable-declarations -Wconversion -Wno-c++98-compat -Wno-float-equal -Wno-cast-align -Wno-global-constructors -Wno-c++98-compat-pedantic -Wno-exit-time-destructors -Wno-format-nonliteral -Wno-weak-template-vtables"
#
#-Wno-weak-vtables
# FIXME: -Wno-weak-vtables -Wno-missing-variable-declarations -Wno-conversion -Wno-exit-time-destructors
#

View File

@ -17,10 +17,82 @@ namespace netlist
namespace devices
{
// -----------------------------------------------------------------------------
// nld_base_proxy
// -----------------------------------------------------------------------------
nld_base_proxy::nld_base_proxy(netlist_t &anetlist, const pstring &name,
logic_t *inout_proxied, detail::core_terminal_t *proxy_inout)
: device_t(anetlist, name)
{
m_logic_family = inout_proxied->logic_family();
m_term_proxied = inout_proxied;
m_proxy_term = proxy_inout;
}
nld_base_proxy::~nld_base_proxy()
{
}
// ----------------------------------------------------------------------------------------
// nld_a_to_d_proxy
// ----------------------------------------------------------------------------------------
nld_base_a_to_d_proxy::nld_base_a_to_d_proxy(netlist_t &anetlist, const pstring &name,
logic_input_t *in_proxied, detail::core_terminal_t *in_proxy)
: nld_base_proxy(anetlist, name, in_proxied, in_proxy)
, m_Q(*this, "Q")
{
}
nld_base_a_to_d_proxy::~nld_base_a_to_d_proxy() {}
nld_a_to_d_proxy::nld_a_to_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *in_proxied)
: nld_base_a_to_d_proxy(anetlist, name, in_proxied, &m_I)
, m_I(*this, "I")
{
}
nld_a_to_d_proxy::~nld_a_to_d_proxy()
{
}
NETLIB_RESET(a_to_d_proxy)
{
}
NETLIB_UPDATE(a_to_d_proxy)
{
nl_assert(m_logic_family != nullptr);
// FIXME: Variable supply voltage!
double supply_V = logic_family().fixed_V();
if (supply_V == 0.0) supply_V = 5.0;
if (m_I.Q_Analog() > logic_family().high_thresh_V(0.0, supply_V))
out().push(1, NLTIME_FROM_NS(1));
else if (m_I.Q_Analog() < logic_family().low_thresh_V(0.0, supply_V))
out().push(0, NLTIME_FROM_NS(1));
else
{
// do nothing
}
}
// ----------------------------------------------------------------------------------------
// nld_d_to_a_proxy
// ----------------------------------------------------------------------------------------
nld_base_d_to_a_proxy::nld_base_d_to_a_proxy(netlist_t &anetlist, const pstring &name,
logic_output_t *out_proxied, detail::core_terminal_t &proxy_out)
: nld_base_proxy(anetlist, name, out_proxied, &proxy_out)
, m_I(*this, "I")
{
}
nld_base_d_to_a_proxy::~nld_base_d_to_a_proxy()
{
}
nld_d_to_a_proxy::nld_d_to_a_proxy(netlist_t &anetlist, const pstring &name, logic_output_t *out_proxied)
: nld_base_d_to_a_proxy(anetlist, name, out_proxied, m_RV.m_P)
, m_GNDHack(*this, "_Q")

View File

@ -31,15 +31,9 @@ namespace netlist
{
public:
nld_base_proxy(netlist_t &anetlist, const pstring &name,
logic_t *inout_proxied, detail::core_terminal_t *proxy_inout)
: device_t(anetlist, name)
{
m_logic_family = inout_proxied->logic_family();
m_term_proxied = inout_proxied;
m_proxy_term = proxy_inout;
}
logic_t *inout_proxied, detail::core_terminal_t *proxy_inout);
virtual ~nld_base_proxy() {}
virtual ~nld_base_proxy();
logic_t &term_proxied() const { return *m_term_proxied; }
detail::core_terminal_t &proxy_term() const { return *m_proxy_term; }
@ -65,18 +59,14 @@ namespace netlist
{
public:
virtual ~nld_base_a_to_d_proxy() {}
virtual ~nld_base_a_to_d_proxy();
virtual logic_output_t &out() { return m_Q; }
protected:
nld_base_a_to_d_proxy(netlist_t &anetlist, const pstring &name,
logic_input_t *in_proxied, detail::core_terminal_t *in_proxy)
: nld_base_proxy(anetlist, name, in_proxied, in_proxy)
, m_Q(*this, "Q")
{
}
logic_input_t *in_proxied, detail::core_terminal_t *in_proxy);
private:
@ -87,36 +77,17 @@ namespace netlist
NETLIB_OBJECT_DERIVED(a_to_d_proxy, base_a_to_d_proxy)
{
public:
nld_a_to_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *in_proxied)
: nld_base_a_to_d_proxy(anetlist, name, in_proxied, &m_I)
, m_I(*this, "I")
{
}
nld_a_to_d_proxy(netlist_t &anetlist, const pstring &name, logic_input_t *in_proxied);
virtual ~nld_a_to_d_proxy() {}
virtual ~nld_a_to_d_proxy();
analog_input_t m_I;
protected:
NETLIB_RESETI() { }
NETLIB_RESETI();
NETLIB_UPDATEI();
NETLIB_UPDATEI()
{
nl_assert(m_logic_family != nullptr);
// FIXME: Variable supply voltage!
double supply_V = logic_family().fixed_V();
if (supply_V == 0.0) supply_V = 5.0;
if (m_I.Q_Analog() > logic_family().high_thresh_V(0.0, supply_V))
out().push(1, NLTIME_FROM_NS(1));
else if (m_I.Q_Analog() < logic_family().low_thresh_V(0.0, supply_V))
out().push(0, NLTIME_FROM_NS(1));
else
{
// do nothing
}
}
private:
};
@ -127,17 +98,13 @@ namespace netlist
NETLIB_OBJECT_DERIVED(base_d_to_a_proxy, base_proxy)
{
public:
virtual ~nld_base_d_to_a_proxy() {}
virtual ~nld_base_d_to_a_proxy();
virtual logic_input_t &in() { return m_I; }
protected:
nld_base_d_to_a_proxy(netlist_t &anetlist, const pstring &name,
logic_output_t *out_proxied, detail::core_terminal_t &proxy_out)
: nld_base_proxy(anetlist, name, out_proxied, &proxy_out)
, m_I(*this, "I")
{
}
logic_output_t *out_proxied, detail::core_terminal_t &proxy_out);
logic_input_t m_I;

View File

@ -49,10 +49,24 @@ void object_t::operator delete (void * mem)
}
nl_exception::~nl_exception()
{
}
// ----------------------------------------------------------------------------------------
// logic_family_ttl_t
// ----------------------------------------------------------------------------------------
logic_family_desc_t::logic_family_desc_t()
{
}
logic_family_desc_t::~logic_family_desc_t()
{
}
class logic_family_ttl_t : public logic_family_desc_t
{
public:
@ -761,6 +775,9 @@ logic_net_t::logic_net_t(netlist_t &nl, const pstring &aname, detail::core_termi
{
}
logic_net_t::~logic_net_t()
{
}
// ----------------------------------------------------------------------------------------
// analog_net_t
@ -772,6 +789,10 @@ analog_net_t::analog_net_t(netlist_t &nl, const pstring &aname, detail::core_ter
{
}
analog_net_t::~analog_net_t()
{
}
// ----------------------------------------------------------------------------------------
// core_terminal_t
// ----------------------------------------------------------------------------------------
@ -785,6 +806,10 @@ detail::core_terminal_t::core_terminal_t(core_device_t &dev, const pstring &anam
{
}
detail::core_terminal_t::~core_terminal_t()
{
}
void detail::core_terminal_t::reset()
{
if (is_type(OUTPUT))
@ -803,6 +828,13 @@ void detail::core_terminal_t::set_net(net_t *anet)
m_net = nullptr;
}
analog_t::~analog_t()
{
}
logic_t::~logic_t()
{
}
// ----------------------------------------------------------------------------------------
// terminal_t
@ -854,6 +886,11 @@ logic_output_t::logic_output_t(core_device_t &dev, const pstring &aname)
netlist().setup().register_term(*this);
}
logic_output_t::~logic_output_t()
{
}
void logic_output_t::initial(const netlist_sig_t val)
{
net().initial(val);
@ -883,6 +920,10 @@ analog_output_t::analog_output_t(core_device_t &dev, const pstring &aname)
netlist().setup().register_term(*this);
}
analog_output_t::~analog_output_t()
{
}
void analog_output_t::initial(const nl_double val)
{
net().m_cur_Analog = val;
@ -899,6 +940,10 @@ logic_input_t::logic_input_t(core_device_t &dev, const pstring &aname)
netlist().setup().register_term(*this);
}
logic_input_t::~logic_input_t()
{
}
// ----------------------------------------------------------------------------------------
// Parameters ...
// ----------------------------------------------------------------------------------------
@ -910,6 +955,10 @@ param_t::param_t(const param_type_t atype, device_t &device, const pstring &name
device.setup().register_param(this->name(), *this);
}
param_t::~param_t()
{
}
void param_t::update_param()
{
device().update_param();
@ -958,6 +1007,15 @@ param_ptr_t::param_ptr_t(device_t &device, const pstring name, uint8_t * val)
//netlist().save(*this, m_param, "m_param");
}
void param_str_t::changed()
{
}
void param_model_t::changed()
{
m_map.clear();
}
const pstring param_model_t::model_value_str(const pstring &entity)
{
if (m_map.size() == 0)
@ -972,6 +1030,10 @@ nl_double param_model_t::model_value(const pstring &entity)
return netlist().setup().model_value(m_map, entity);
}
void param_data_t::changed()
{
}
std::unique_ptr<plib::pistream> param_data_t::stream()
{
return device().netlist().setup().get_data_stream(Value());

View File

@ -209,7 +209,7 @@ namespace netlist
: plib::pexception(text) { }
/*! Copy constructor. */
nl_exception(const nl_exception &e) : plib::pexception(e) { }
virtual ~nl_exception() {}
virtual ~nl_exception();
};
class logic_output_t;
@ -234,8 +234,8 @@ namespace netlist
class logic_family_desc_t
{
public:
logic_family_desc_t() {}
virtual ~logic_family_desc_t() {}
logic_family_desc_t();
virtual ~logic_family_desc_t();
virtual plib::owned_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_t &anetlist, const pstring &name,
logic_output_t *proxied) const = 0;
@ -496,7 +496,7 @@ namespace netlist
core_terminal_t(core_device_t &dev, const pstring &aname,
const type_t type, const state_e state);
virtual ~core_terminal_t() { }
virtual ~core_terminal_t();
void set_net(net_t *anet);
void clear_net();
@ -532,6 +532,7 @@ namespace netlist
: core_terminal_t(dev, aname, type, state)
{
}
virtual ~analog_t();
const analog_net_t & net() const NL_NOEXCEPT;
analog_net_t & net() NL_NOEXCEPT;
@ -613,6 +614,7 @@ namespace netlist
, m_proxy(nullptr)
{
}
virtual ~logic_t();
bool has_proxy() const { return (m_proxy != nullptr); }
devices::nld_base_proxy *get_proxy() const { return m_proxy; }
@ -635,6 +637,7 @@ namespace netlist
{
public:
logic_input_t(core_device_t &dev, const pstring &aname);
virtual ~logic_input_t();
netlist_sig_t Q() const NL_NOEXCEPT;
@ -750,7 +753,7 @@ namespace netlist
public:
logic_net_t(netlist_t &nl, const pstring &aname, detail::core_terminal_t *mr = nullptr);
virtual ~logic_net_t() { }
virtual ~logic_net_t();
netlist_sig_t Q() const { return m_cur_Q; }
netlist_sig_t new_Q() const { return m_new_Q; }
@ -794,7 +797,7 @@ namespace netlist
analog_net_t(netlist_t &nl, const pstring &aname, detail::core_terminal_t *mr = nullptr);
virtual ~analog_net_t() { }
virtual ~analog_net_t();
nl_double Q_Analog() const { return m_cur_Analog; }
nl_double &Q_Analog_state_ptr() { return m_cur_Analog; }
@ -817,6 +820,7 @@ namespace netlist
public:
logic_output_t(core_device_t &dev, const pstring &aname);
virtual ~logic_output_t();
void initial(const netlist_sig_t val);
@ -834,6 +838,7 @@ namespace netlist
P_PREVENT_COPYING(analog_output_t)
public:
analog_output_t(core_device_t &dev, const pstring &aname);
virtual ~analog_output_t();
void push(const nl_double val) NL_NOEXCEPT { set_Q(val); }
void initial(const nl_double val);
@ -861,7 +866,7 @@ namespace netlist
};
param_t(const param_type_t atype, device_t &device, const pstring &name);
virtual ~param_t() {}
virtual ~param_t();
param_type_t param_type() const { return m_param_type; }
@ -937,7 +942,7 @@ namespace netlist
}
}
protected:
virtual void changed() { }
virtual void changed();
pstring Value() const { return m_param; }
private:
pstring m_param;
@ -954,7 +959,7 @@ namespace netlist
const pstring model_value_str(const pstring &entity);
const pstring model_type();
protected:
virtual void changed() override { m_map.clear(); }
virtual void changed() override;
private:
model_map_t m_map;
};
@ -966,7 +971,7 @@ namespace netlist
: param_str_t(device, name, "") { }
std::unique_ptr<plib::pistream> stream();
protected:
virtual void changed() override { }
virtual void changed() override;
};
// -----------------------------------------------------------------------------

View File

@ -14,6 +14,18 @@
namespace netlist { namespace factory
{
element_t::element_t(const pstring &name, const pstring &classname,
const pstring &def_param)
: m_name(name), m_classname(classname), m_def_param(def_param)
{
}
element_t::~element_t()
{
}
// ----------------------------------------------------------------------------------------
// net_device_t_base_factory
// ----------------------------------------------------------------------------------------
@ -51,7 +63,7 @@ factory::element_t * list_t::factory_by_name(const pstring &devname)
plib::owned_ptr<device_t> library_element_t::Create(netlist_t &anetlist, const pstring &name)
{
return plib::owned_ptr<device_t>::Create<wrapper>(anetlist, name);
return plib::owned_ptr<device_t>::Create<NETLIB_NAME(wrapper)>(anetlist, name);
}
void library_element_t::macro_actions(netlist_t &anetlist, const pstring &name)
@ -61,5 +73,13 @@ void library_element_t::macro_actions(netlist_t &anetlist, const pstring &name)
anetlist.setup().namespace_pop();
}
NETLIB_RESET(wrapper)
{
}
NETLIB_UPDATE(wrapper)
{
}
} }

View File

@ -30,11 +30,8 @@ namespace netlist { namespace factory
P_PREVENT_COPYING(element_t)
public:
element_t(const pstring &name, const pstring &classname,
const pstring &def_param)
: m_name(name), m_classname(classname), m_def_param(def_param)
{}
virtual ~element_t() {}
const pstring &def_param);
virtual ~element_t();
virtual plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) = 0;
virtual void macro_actions(netlist_t &anetlist, const pstring &name) {}
@ -117,6 +114,18 @@ namespace netlist { namespace factory
// factory_lib_entry_t: factory class to wrap macro based chips/elements
// -----------------------------------------------------------------------------
class NETLIB_NAME(wrapper) : public device_t
{
public:
NETLIB_NAME(wrapper)(netlist_t &anetlist, const pstring &name)
: device_t(anetlist, name)
{
}
protected:
NETLIB_RESETI();
NETLIB_UPDATEI();
};
class library_element_t : public element_t
{
P_PREVENT_COPYING(library_element_t)
@ -126,18 +135,6 @@ namespace netlist { namespace factory
const pstring &def_param)
: element_t(name, classname, def_param), m_setup(setup) { }
class wrapper : public device_t
{
public:
wrapper(netlist_t &anetlist, const pstring &name)
: device_t(anetlist, name)
{
}
protected:
NETLIB_RESETI() { }
NETLIB_UPDATEI() { }
};
plib::owned_ptr<device_t> Create(netlist_t &anetlist, const pstring &name) override;
void macro_actions(netlist_t &anetlist, const pstring &name) override;

View File

@ -1080,4 +1080,22 @@ std::unique_ptr<plib::pistream> source_file_t::stream(const pstring &name)
return plib::make_unique_base<plib::pistream, plib::pifilestream>(m_filename);
}
bool source_proc_t::parse(const pstring &name)
{
if (name == m_setup_func_name)
{
m_setup_func(setup());
return true;
}
else
return false;
}
std::unique_ptr<plib::pistream> source_proc_t::stream(const pstring &name)
{
std::unique_ptr<plib::pistream> p(nullptr);
return p;
}
}

View File

@ -373,22 +373,9 @@ namespace netlist
{
}
virtual bool parse(const pstring &name) override
{
if (name == m_setup_func_name)
{
m_setup_func(setup());
return true;
}
else
return false;
}
virtual bool parse(const pstring &name) override;
virtual std::unique_ptr<plib::pistream> stream(const pstring &name) override;
virtual std::unique_ptr<plib::pistream> stream(const pstring &name) override
{
std::unique_ptr<plib::pistream> p(nullptr);
return p;
}
private:
void (*m_setup_func)(setup_t &);
pstring m_setup_func_name;

View File

@ -26,41 +26,75 @@ pexception::pexception(const pstring text)
m_text = text;
}
pexception::~pexception() noexcept
{
}
file_e::file_e(const pstring fmt, const pstring &filename)
: pexception(pfmt(fmt)(filename))
{
}
file_e::~file_e() noexcept
{
}
file_open_e::file_open_e(const pstring &filename)
: file_e("File open failed: {}", filename)
{
}
file_open_e::~file_open_e() noexcept
{
}
file_read_e::file_read_e(const pstring &filename)
: file_e("File read failed: {}", filename)
{
}
file_read_e::~file_read_e() noexcept
{
}
file_write_e::file_write_e(const pstring &filename)
: file_e("File write failed: {}", filename)
{
}
file_write_e::~file_write_e() noexcept
{
}
null_argument_e::null_argument_e(const pstring &argument)
: pexception(pfmt("Null argument passed: {}")(argument))
{
}
null_argument_e::~null_argument_e() noexcept
{
}
out_of_mem_e::out_of_mem_e(const pstring &location)
: pexception(pfmt("Out of memory: {}")(location))
{
}
fpexception::fpexception(const pstring &text)
out_of_mem_e::~out_of_mem_e() noexcept
{
}
fpexception_e::fpexception_e(const pstring &text)
: pexception(pfmt("Out of memory: {}")(text))
{
}
fpexception_e::~fpexception_e() noexcept
{
}
bool fpsignalenabler::m_enable = false;
fpsignalenabler::fpsignalenabler(unsigned fpexceptions)

View File

@ -21,10 +21,10 @@ namespace plib {
class pexception : public std::exception
{
public:
pexception(const pstring text);
explicit pexception(const pstring text);
pexception(const pexception &e) : std::exception(e) { m_text = e.m_text; }
virtual ~pexception() noexcept {}
virtual ~pexception() noexcept;
const pstring &text() { return m_text; }
@ -36,46 +36,60 @@ class file_e : public plib::pexception
{
public:
explicit file_e(const pstring fmt, const pstring &filename);
file_e(const file_e &e) : pexception(e) { }
virtual ~file_e() noexcept;
};
class file_open_e : public file_e
{
public:
explicit file_open_e(const pstring &filename);
file_open_e(const file_open_e &e) : file_e(e) { }
virtual ~file_open_e() noexcept;
};
class file_read_e : public file_e
{
public:
explicit file_read_e(const pstring &filename);
file_read_e(const file_read_e &e) : file_e(e) { }
virtual ~file_read_e() noexcept;
};
class file_write_e : public file_e
{
public:
explicit file_write_e(const pstring &filename);
file_write_e(const file_write_e &e) : file_e(e) { }
virtual ~file_write_e() noexcept;
};
class null_argument_e : public plib::pexception
{
public:
explicit null_argument_e(const pstring &argument);
null_argument_e(const null_argument_e &e) : pexception(e) { }
virtual ~null_argument_e() noexcept;
};
class out_of_mem_e : public plib::pexception
{
public:
explicit out_of_mem_e(const pstring &location);
out_of_mem_e(const out_of_mem_e &e) : pexception(e) { }
virtual ~out_of_mem_e() noexcept;
};
/* FIXME: currently only a stub for later use. More use could be added by
* using -fnon-call-exceptions" and sigaction to enable c++ exception supported.
*/
class fpexception : public pexception
class fpexception_e : public pexception
{
public:
fpexception(const pstring &text);
fpexception_e(const pstring &text);
fpexception_e(const fpexception_e &e) : pexception(e) { }
virtual ~fpexception_e() noexcept;
};
static const unsigned FP_INEXACT = 0x0001;

View File

@ -17,6 +17,11 @@
#include "palloc.h"
namespace plib {
plog_dispatch_intf::~plog_dispatch_intf()
{
}
pfmt::pfmt(const pstring &fmt)
: m_str(m_str_buf), m_allocated(0), m_arg(0)
{

View File

@ -263,7 +263,7 @@ class plog_dispatch_intf
template<plog_level::e, bool> friend class plog_channel;
public:
virtual ~plog_dispatch_intf() { }
virtual ~plog_dispatch_intf();
protected:
virtual void vlog(const plog_level &l, const pstring &ls) const = 0;
};

View File

@ -22,11 +22,23 @@ namespace plib {
{
}
option_group::~option_group()
{
}
option_example::~option_example()
{
}
option::option(options &parent, pstring ashort, pstring along, pstring help, bool has_argument)
: option_base(parent, help), m_short(ashort), m_long(along), m_has_argument(has_argument)
{
}
option::~option()
{
}
int option_str::parse(pstring argument)
{
m_val = argument;

View File

@ -39,6 +39,7 @@ class option_group : public option_base
public:
option_group(options &parent, pstring group, pstring help)
: option_base(parent, help), m_group(group) { }
~option_group();
pstring group() { return m_group; }
private:
@ -50,6 +51,7 @@ class option_example : public option_base
public:
option_example(options &parent, pstring group, pstring help)
: option_base(parent, help), m_example(group) { }
~option_example();
pstring example() { return m_example; }
private:
@ -61,6 +63,7 @@ class option : public option_base
{
public:
option(options &parent, pstring ashort, pstring along, pstring help, bool has_argument);
~option();
/* no_argument options will be called with "" argument */

View File

@ -15,6 +15,16 @@ namespace plib {
// A simple tokenizer
// ----------------------------------------------------------------------------------------
ptokenizer::ptokenizer(pistream &strm)
: m_strm(strm), m_lineno(0), m_cur_line(""), m_px(m_cur_line.begin()), m_unget(0), m_string('"')
{
}
ptokenizer::~ptokenizer()
{
}
pstring ptokenizer::currentline_str()
{
return m_cur_line;

View File

@ -22,11 +22,9 @@ class ptokenizer
{
P_PREVENT_COPYING(ptokenizer)
public:
virtual ~ptokenizer() {}
explicit ptokenizer(pistream &strm);
explicit ptokenizer(pistream &strm)
: m_strm(strm), m_lineno(0), m_cur_line(""), m_px(m_cur_line.begin()), m_unget(0), m_string('"')
{}
virtual ~ptokenizer();
enum token_type
{

View File

@ -60,4 +60,9 @@ template<> void state_manager_t::save_item(const void *owner, callback_t &state,
state.register_state(*this, stname);
}
state_manager_t::callback_t::~callback_t()
{
}
}

View File

@ -62,7 +62,7 @@ public:
public:
using list_t = std::vector<callback_t *>;
virtual ~callback_t() { }
virtual ~callback_t();
virtual void register_state(state_manager_t &manager, const pstring &module) = 0;
virtual void on_pre_save() = 0;

View File

@ -14,10 +14,19 @@
#include "palloc.h"
namespace plib {
pstream::~pstream()
{
}
// -----------------------------------------------------------------------------
// pistream: input stream
// -----------------------------------------------------------------------------
pistream::~pistream()
{
}
bool pistream::readline(pstring &line)
{
char c = 0;
@ -44,6 +53,10 @@ bool pistream::readline(pstring &line)
// postream: output stream
// -----------------------------------------------------------------------------
postream::~postream()
{
}
void postream::write(pistream &strm)
{
char buf[1024];
@ -142,6 +155,10 @@ pstdin::pstdin()
/* nothing to do */
}
pstdin::~pstdin()
{
}
// -----------------------------------------------------------------------------
// Output file stream
// -----------------------------------------------------------------------------
@ -209,6 +226,11 @@ pstream::pos_type pofilestream::vtell()
return static_cast<pos_type>(ret);
}
postringstream::~postringstream()
{
}
// -----------------------------------------------------------------------------
// pstderr: write to stderr
// -----------------------------------------------------------------------------
@ -218,6 +240,10 @@ pstderr::pstderr()
{
}
pstderr::~pstderr()
{
}
// -----------------------------------------------------------------------------
// pstdout: write to stdout
// -----------------------------------------------------------------------------
@ -227,6 +253,10 @@ pstdout::pstdout()
{
}
pstdout::~pstdout()
{
}
// -----------------------------------------------------------------------------
// Memory stream
// -----------------------------------------------------------------------------
@ -273,6 +303,10 @@ pimemstream::pos_type pimemstream::vtell()
return m_pos;
}
pistringstream::~pistringstream()
{
}
// -----------------------------------------------------------------------------
// Output memory stream
// -----------------------------------------------------------------------------
@ -333,4 +367,9 @@ pstream::pos_type pomemstream::vtell()
return m_pos;
}
pstream_fmt_writer_t::~pstream_fmt_writer_t()
{
}
}

View File

@ -32,9 +32,7 @@ public:
explicit pstream(const unsigned flags) : m_flags(flags)
{
}
virtual ~pstream()
{
}
virtual ~pstream();
bool seekable() const { return ((m_flags & FLAG_SEEKABLE) != 0); }
@ -79,7 +77,7 @@ class pistream : public pstream
public:
explicit pistream(const unsigned flags) : pstream(flags) {}
virtual ~pistream() {}
virtual ~pistream();
bool eof() const { return ((flags() & FLAG_EOF) != 0); }
@ -115,7 +113,7 @@ class postream : public pstream
public:
explicit postream(unsigned flags) : pstream(flags) {}
virtual ~postream() {}
virtual ~postream();
/* this digests linux & dos/windows text files */
@ -184,7 +182,7 @@ class postringstream : public postream
public:
postringstream() : postream(0) { }
virtual ~postringstream() { }
virtual ~postringstream();
const pstringbuffer &str() { return m_buf; }
@ -238,6 +236,7 @@ class pstderr : public pofilestream
P_PREVENT_COPYING(pstderr)
public:
pstderr();
virtual ~pstderr();
};
// -----------------------------------------------------------------------------
@ -249,6 +248,7 @@ class pstdout : public pofilestream
P_PREVENT_COPYING(pstdout)
public:
pstdout();
virtual ~pstdout();
};
// -----------------------------------------------------------------------------
@ -290,6 +290,7 @@ class pstdin : public pifilestream
public:
pstdin();
virtual ~pstdin();
};
// -----------------------------------------------------------------------------
@ -325,8 +326,8 @@ class pistringstream : public pimemstream
{
P_PREVENT_COPYING(pistringstream)
public:
pistringstream(const pstring &str) : pimemstream(str.c_str(), str.len()), m_str(str) { }
virtual ~pistringstream();
private:
/* only needed for a reference till destruction */
@ -343,7 +344,7 @@ class pstream_fmt_writer_t : public plib::pfmt_writer_t<>
public:
explicit pstream_fmt_writer_t(postream &strm) : m_strm(strm) {}
virtual ~pstream_fmt_writer_t() { }
virtual ~pstream_fmt_writer_t();
protected:
virtual void vdowrite(const pstring &ls) const override

View File

@ -102,25 +102,26 @@ public:
{
}
virtual std::unique_ptr<plib::pistream> stream(const pstring &file) override
{
pstring name = m_folder + "/" + file;
try
{
auto strm = plib::make_unique_base<plib::pistream, plib::pifilestream>(name);
return strm;
}
catch (plib::pexception e)
{
}
return std::unique_ptr<plib::pistream>(nullptr);
}
virtual std::unique_ptr<plib::pistream> stream(const pstring &file) override;
private:
pstring m_folder;
};
std::unique_ptr<plib::pistream> netlist_data_folder_t::stream(const pstring &file)
{
pstring name = m_folder + "/" + file;
try
{
auto strm = plib::make_unique_base<plib::pistream, plib::pifilestream>(name);
return strm;
}
catch (plib::pexception e)
{
}
return std::unique_ptr<plib::pistream>(nullptr);
}
class netlist_tool_t : public netlist::netlist_t
{
@ -182,18 +183,20 @@ public:
protected:
void vlog(const plib::plog_level &l, const pstring &ls) const override
{
pstring err = plib::pfmt("{}: {}\n")(l.name())(ls.c_str());
pout("{}", err);
if (l == plib::plog_level::FATAL)
throw netlist::nl_exception(err);
}
void vlog(const plib::plog_level &l, const pstring &ls) const override;
private:
netlist::setup_t *m_setup;
};
void netlist_tool_t::vlog(const plib::plog_level &l, const pstring &ls) const
{
pstring err = plib::pfmt("{}: {}\n")(l.name())(ls.c_str());
pout("{}", err);
if (l == plib::plog_level::FATAL)
throw netlist::nl_exception(err);
}
// FIXME: usage should go elsewhere
void usage(tool_options_t &opts);

View File

@ -0,0 +1,562 @@
// license:GPL-2.0+
// copyright-holders:Couriersud
/*
* nld_matrix_solver.cpp
*
*/
#include "nld_matrix_solver.h"
#include "plib/putil.h"
namespace netlist
{
namespace devices
{
proxied_analog_output_t::~proxied_analog_output_t()
{
}
terms_t::terms_t()
: m_railstart(0)
, m_last_V(0.0)
, m_DD_n_m_1(0.0)
, m_h_n_m_1(1e-9)
{
}
void terms_t::clear()
{
m_term.clear();
m_net_other.clear();
m_gt.clear();
m_go.clear();
m_Idr.clear();
m_other_curanalog.clear();
}
void terms_t::add(terminal_t *term, int net_other, bool sorted)
{
if (sorted)
for (unsigned i=0; i < m_net_other.size(); i++)
{
if (m_net_other[i] > net_other)
{
plib::container::insert_at(m_term, i, term);
plib::container::insert_at(m_net_other, i, net_other);
plib::container::insert_at(m_gt, i, 0.0);
plib::container::insert_at(m_go, i, 0.0);
plib::container::insert_at(m_Idr, i, 0.0);
plib::container::insert_at(m_other_curanalog, i, nullptr);
return;
}
}
m_term.push_back(term);
m_net_other.push_back(net_other);
m_gt.push_back(0.0);
m_go.push_back(0.0);
m_Idr.push_back(0.0);
m_other_curanalog.push_back(nullptr);
}
void terms_t::set_pointers()
{
for (unsigned i = 0; i < count(); i++)
{
m_term[i]->set_ptrs(&m_gt[i], &m_go[i], &m_Idr[i]);
m_other_curanalog[i] = m_term[i]->m_otherterm->net().m_cur_Analog.ptr();
}
}
// ----------------------------------------------------------------------------------------
// matrix_solver
// ----------------------------------------------------------------------------------------
matrix_solver_t::matrix_solver_t(netlist_t &anetlist, const pstring &name,
const eSortType sort, const solver_parameters_t *params)
: device_t(anetlist, name)
, m_params(*params)
, m_stat_calculations(*this, "m_stat_calculations", 0)
, m_stat_newton_raphson(*this, "m_stat_newton_raphson", 0)
, m_stat_vsolver_calls(*this, "m_stat_vsolver_calls", 0)
, m_iterative_fail(*this, "m_iterative_fail", 0)
, m_iterative_total(*this, "m_iterative_total", 0)
, m_last_step(*this, "m_last_step", netlist_time::zero())
, m_fb_sync(*this, "FB_sync")
, m_Q_sync(*this, "Q_sync")
, m_sort(sort)
{
connect_post_start(m_fb_sync, m_Q_sync);
}
matrix_solver_t::~matrix_solver_t()
{
for (unsigned k = 0; k < m_terms.size(); k++)
{
plib::pfree(m_terms[k]);
}
}
void matrix_solver_t::setup_base(analog_net_t::list_t &nets)
{
log().debug("New solver setup\n");
m_nets.clear();
m_terms.clear();
for (auto & net : nets)
{
m_nets.push_back(net);
m_terms.push_back(plib::palloc<terms_t>());
m_rails_temp.push_back(plib::palloc<terms_t>());
}
for (std::size_t k = 0; k < nets.size(); k++)
{
analog_net_t *net = nets[k];
log().debug("setting up net\n");
net->set_solver(this);
for (auto &p : net->m_core_terms)
{
log().debug("{1} {2} {3}\n", p->name(), net->name(), net->isRailNet());
switch (p->type())
{
case terminal_t::TERMINAL:
if (p->device().is_timestep())
if (!plib::container::contains(m_step_devices, &p->device()))
m_step_devices.push_back(&p->device());
if (p->device().is_dynamic())
if (!plib::container::contains(m_dynamic_devices, &p->device()))
m_dynamic_devices.push_back(&p->device());
{
terminal_t *pterm = dynamic_cast<terminal_t *>(p);
add_term(k, pterm);
}
log().debug("Added terminal {1}\n", p->name());
break;
case terminal_t::INPUT:
{
proxied_analog_output_t *net_proxy_output = nullptr;
for (auto & input : m_inps)
if (input->m_proxied_net == &p->net())
{
net_proxy_output = input.get();
break;
}
if (net_proxy_output == nullptr)
{
auto net_proxy_output_u = plib::make_unique<proxied_analog_output_t>(*this, this->name() + "." + plib::pfmt("m{1}")(m_inps.size()));
net_proxy_output = net_proxy_output_u.get();
m_inps.push_back(std::move(net_proxy_output_u));
nl_assert(p->net().is_analog());
net_proxy_output->m_proxied_net = static_cast<analog_net_t *>(&p->net());
}
net_proxy_output->net().add_terminal(*p);
// FIXME: repeated
net_proxy_output->net().rebuild_list();
log().debug("Added input\n");
}
break;
case terminal_t::OUTPUT:
case terminal_t::PARAM:
log().fatal("unhandled element found\n");
break;
}
}
log().debug("added net with {1} populated connections\n", net->m_core_terms.size());
}
/* now setup the matrix */
setup_matrix();
}
void matrix_solver_t::setup_matrix()
{
const std::size_t iN = m_nets.size();
for (std::size_t k = 0; k < iN; k++)
{
m_terms[k]->m_railstart = m_terms[k]->count();
for (std::size_t i = 0; i < m_rails_temp[k]->count(); i++)
this->m_terms[k]->add(m_rails_temp[k]->terms()[i], m_rails_temp[k]->net_other()[i], false);
m_rails_temp[k]->clear(); // no longer needed
m_terms[k]->set_pointers();
}
for (unsigned k = 0; k < iN; k++)
plib::pfree(m_rails_temp[k]); // no longer needed
m_rails_temp.clear();
/* Sort in descending order by number of connected matrix voltages.
* The idea is, that for Gauss-Seidel algo the first voltage computed
* depends on the greatest number of previous voltages thus taking into
* account the maximum amout of information.
*
* This actually improves performance on popeye slightly. Average
* GS computations reduce from 2.509 to 2.370
*
* Smallest to largest : 2.613
* Unsorted : 2.509
* Largest to smallest : 2.370
*
* Sorting as a general matrix pre-conditioning is mentioned in
* literature but I have found no articles about Gauss Seidel.
*
* For Gaussian Elimination however increasing order is better suited.
* FIXME: Even better would be to sort on elements right of the matrix diagonal.
*
*/
if (m_sort != NOSORT)
{
int sort_order = (m_sort == DESCENDING ? 1 : -1);
for (unsigned k = 0; k < iN - 1; k++)
for (unsigned i = k+1; i < iN; i++)
{
if ((static_cast<int>(m_terms[k]->m_railstart) - static_cast<int>(m_terms[i]->m_railstart)) * sort_order < 0)
{
std::swap(m_terms[i], m_terms[k]);
std::swap(m_nets[i], m_nets[k]);
}
}
for (unsigned k = 0; k < iN; k++)
{
int *other = m_terms[k]->net_other();
for (unsigned i = 0; i < m_terms[k]->count(); i++)
if (other[i] != -1)
other[i] = get_net_idx(&m_terms[k]->terms()[i]->m_otherterm->net());
}
}
/* create a list of non zero elements. */
for (unsigned k = 0; k < iN; k++)
{
terms_t * t = m_terms[k];
/* pretty brutal */
int *other = t->net_other();
t->m_nz.clear();
for (unsigned i = 0; i < t->m_railstart; i++)
if (!plib::container::contains(t->m_nz, static_cast<unsigned>(other[i])))
t->m_nz.push_back(static_cast<unsigned>(other[i]));
t->m_nz.push_back(k); // add diagonal
/* and sort */
std::sort(t->m_nz.begin(), t->m_nz.end());
}
/* create a list of non zero elements right of the diagonal
* These list anticipate the population of array elements by
* Gaussian elimination.
*/
for (unsigned k = 0; k < iN; k++)
{
terms_t * t = m_terms[k];
/* pretty brutal */
int *other = t->net_other();
if (k==0)
t->m_nzrd.clear();
else
{
t->m_nzrd = m_terms[k-1]->m_nzrd;
for (auto j = t->m_nzrd.begin(); j != t->m_nzrd.end(); )
{
if (*j < k + 1)
j = t->m_nzrd.erase(j);
else
++j;
}
}
for (unsigned i = 0; i < t->m_railstart; i++)
if (!plib::container::contains(t->m_nzrd, static_cast<unsigned>(other[i])) && other[i] >= static_cast<int>(k + 1))
t->m_nzrd.push_back(static_cast<unsigned>(other[i]));
/* and sort */
std::sort(t->m_nzrd.begin(), t->m_nzrd.end());
}
/* create a list of non zero elements below diagonal k
* This should reduce cache misses ...
*/
bool **touched = new bool*[iN];
for (unsigned k=0; k<iN; k++)
touched[k] = new bool[iN];
for (unsigned k = 0; k < iN; k++)
{
for (unsigned j = 0; j < iN; j++)
touched[k][j] = false;
for (unsigned j = 0; j < m_terms[k]->m_nz.size(); j++)
touched[k][m_terms[k]->m_nz[j]] = true;
}
unsigned ops = 0;
for (unsigned k = 0; k < iN; k++)
{
ops++; // 1/A(k,k)
for (unsigned row = k + 1; row < iN; row++)
{
if (touched[row][k])
{
ops++;
if (!plib::container::contains(m_terms[k]->m_nzbd, row))
m_terms[k]->m_nzbd.push_back(row);
for (unsigned col = k + 1; col < iN; col++)
if (touched[k][col])
{
touched[row][col] = true;
ops += 2;
}
}
}
}
log().verbose("Number of mults/adds for {1}: {2}", name(), ops);
if ((0))
for (unsigned k = 0; k < iN; k++)
{
pstring line = plib::pfmt("{1}")(k, "3");
for (unsigned j = 0; j < m_terms[k]->m_nzrd.size(); j++)
line += plib::pfmt(" {1}")(m_terms[k]->m_nzrd[j], "3");
log().verbose("{1}", line);
}
/*
* save states
*/
for (unsigned k = 0; k < iN; k++)
{
pstring num = plib::pfmt("{1}")(k);
netlist().save(*this, m_terms[k]->m_last_V, "lastV." + num);
netlist().save(*this, m_terms[k]->m_DD_n_m_1, "m_DD_n_m_1." + num);
netlist().save(*this, m_terms[k]->m_h_n_m_1, "m_h_n_m_1." + num);
netlist().save(*this, m_terms[k]->go(),"GO" + num, m_terms[k]->count());
netlist().save(*this, m_terms[k]->gt(),"GT" + num, m_terms[k]->count());
netlist().save(*this, m_terms[k]->Idr(),"IDR" + num , m_terms[k]->count());
}
for (unsigned k=0; k<iN; k++)
delete [] touched[k];
delete [] touched;
}
void matrix_solver_t::update_inputs()
{
// avoid recursive calls. Inputs are updated outside this call
for (auto &inp : m_inps)
inp->push(inp->m_proxied_net->Q_Analog());
}
void matrix_solver_t::update_dynamic()
{
/* update all non-linear devices */
for (auto &dyn : m_dynamic_devices)
dyn->update_terminals();
}
void matrix_solver_t::reset()
{
m_last_step = netlist_time::zero();
}
void matrix_solver_t::update() NL_NOEXCEPT
{
const netlist_time new_timestep = solve();
if (m_params.m_dynamic && has_timestep_devices() && new_timestep > netlist_time::zero())
{
m_Q_sync.net().force_queue_execution();
m_Q_sync.net().reschedule_in_queue(new_timestep);
}
}
void matrix_solver_t::update_forced()
{
ATTR_UNUSED const netlist_time new_timestep = solve();
if (m_params.m_dynamic && has_timestep_devices())
{
m_Q_sync.net().force_queue_execution();
m_Q_sync.net().reschedule_in_queue(netlist_time::from_double(m_params.m_min_timestep));
}
}
void matrix_solver_t::step(const netlist_time &delta)
{
const nl_double dd = delta.as_double();
for (std::size_t k=0; k < m_step_devices.size(); k++)
m_step_devices[k]->timestep(dd);
}
void matrix_solver_t::solve_base()
{
m_stat_vsolver_calls++;
if (has_dynamic_devices())
{
unsigned this_resched;
unsigned newton_loops = 0;
do
{
update_dynamic();
// Gauss-Seidel will revert to Gaussian elemination if steps exceeded.
this_resched = this->vsolve_non_dynamic(true);
newton_loops++;
} while (this_resched > 1 && newton_loops < m_params.m_nr_loops);
m_stat_newton_raphson += newton_loops;
// reschedule ....
if (this_resched > 1 && !m_Q_sync.net().is_queued())
{
log().warning("NEWTON_LOOPS exceeded on net {1}... reschedule", this->name());
m_Q_sync.net().toggle_new_Q();
m_Q_sync.net().reschedule_in_queue(m_params.m_nt_sync_delay);
}
}
else
{
this->vsolve_non_dynamic(false);
}
}
const netlist_time matrix_solver_t::solve()
{
const netlist_time now = netlist().time();
const netlist_time delta = now - m_last_step;
// We are already up to date. Avoid oscillations.
// FIXME: Make this a parameter!
if (delta < netlist_time::quantum())
return netlist_time::zero();
/* update all terminals for new time step */
m_last_step = now;
step(delta);
solve_base();
const netlist_time next_time_step = compute_next_timestep(delta.as_double());
update_inputs();
return next_time_step;
}
int matrix_solver_t::get_net_idx(detail::net_t *net)
{
for (std::size_t k = 0; k < m_nets.size(); k++)
if (m_nets[k] == net)
return static_cast<int>(k);
return -1;
}
void matrix_solver_t::add_term(std::size_t k, terminal_t *term)
{
if (term->m_otherterm->net().isRailNet())
{
m_rails_temp[k]->add(term, -1, false);
}
else
{
int ot = get_net_idx(&term->m_otherterm->net());
if (ot>=0)
{
m_terms[k]->add(term, ot, true);
}
/* Should this be allowed ? */
else // if (ot<0)
{
m_rails_temp[k]->add(term, ot, true);
log().fatal("found term with missing othernet {1}\n", term->name());
}
}
}
netlist_time matrix_solver_t::compute_next_timestep(const double cur_ts)
{
nl_double new_solver_timestep = m_params.m_max_timestep;
if (m_params.m_dynamic)
{
/*
* FIXME: We should extend the logic to use either all nets or
* only output nets.
*/
for (std::size_t k = 0, iN=m_terms.size(); k < iN; k++)
{
analog_net_t *n = m_nets[k];
terms_t *t = m_terms[k];
const nl_double DD_n = (n->Q_Analog() - t->m_last_V);
const nl_double hn = cur_ts;
//printf("%f %f %f %f\n", DD_n, t->m_DD_n_m_1, hn, t->m_h_n_m_1);
nl_double DD2 = (DD_n / hn - t->m_DD_n_m_1 / t->m_h_n_m_1) / (hn + t->m_h_n_m_1);
nl_double new_net_timestep;
t->m_h_n_m_1 = hn;
t->m_DD_n_m_1 = DD_n;
if (std::fabs(DD2) > NL_FCONST(1e-60)) // avoid div-by-zero
new_net_timestep = std::sqrt(m_params.m_lte / std::fabs(NL_FCONST(0.5)*DD2));
else
new_net_timestep = m_params.m_max_timestep;
if (new_net_timestep < new_solver_timestep)
new_solver_timestep = new_net_timestep;
t->m_last_V = n->Q_Analog();
}
if (new_solver_timestep < m_params.m_min_timestep)
{
//log().warning("Dynamic timestep below min timestep. Consider decreasing MIN_TIMESTEP: {1} us", new_solver_timestep*1.0e6);
new_solver_timestep = m_params.m_min_timestep;
}
}
//if (new_solver_timestep > 10.0 * hn)
// new_solver_timestep = 10.0 * hn;
/*
* FIXME: Factor 2 below is important. Without, we get timing issues. This must be a bug elsewhere.
*/
return std::max(netlist_time::from_double(new_solver_timestep), netlist_time::quantum() * 2);
}
void matrix_solver_t::log_stats()
{
if (this->m_stat_calculations != 0 && this->m_stat_vsolver_calls && this->m_params.m_log_stats)
{
log().verbose("==============================================");
log().verbose("Solver {1}", this->name());
log().verbose(" ==> {1} nets", this->m_nets.size()); //, (*(*groups[i].first())->m_core_terms.first())->name());
log().verbose(" has {1} elements", this->has_dynamic_devices() ? "dynamic" : "no dynamic");
log().verbose(" has {1} elements", this->has_timestep_devices() ? "timestep" : "no timestep");
log().verbose(" {1:6.3} average newton raphson loops",
static_cast<double>(this->m_stat_newton_raphson) / static_cast<double>(this->m_stat_vsolver_calls));
log().verbose(" {1:10} invocations ({2:6.0} Hz) {3:10} gs fails ({4:6.2} %) {5:6.3} average",
this->m_stat_calculations(),
static_cast<double>(this->m_stat_calculations()) / this->netlist().time().as_double(),
this->m_iterative_fail(),
100.0 * static_cast<double>(this->m_iterative_fail())
/ static_cast<double>(this->m_stat_calculations()),
static_cast<double>(this->m_iterative_total()) / static_cast<double>(this->m_stat_calculations()));
}
}
} //namespace devices
} // namespace netlist

View File

@ -41,22 +41,9 @@ class terms_t
P_PREVENT_COPYING(terms_t)
public:
terms_t()
: m_railstart(0)
, m_last_V(0.0)
, m_DD_n_m_1(0.0)
, m_h_n_m_1(1e-9)
{}
terms_t();
void clear()
{
m_term.clear();
m_net_other.clear();
m_gt.clear();
m_go.clear();
m_Idr.clear();
m_other_curanalog.clear();
}
void clear();
void add(terminal_t *term, int net_other, bool sorted);
@ -100,6 +87,7 @@ public:
: analog_output_t(dev, aname)
, m_proxied_net(nullptr)
{ }
virtual ~proxied_analog_output_t();
analog_net_t *m_proxied_net; // only for proxy nets in analog input logic
};
@ -118,21 +106,7 @@ public:
};
matrix_solver_t(netlist_t &anetlist, const pstring &name,
const eSortType sort, const solver_parameters_t *params)
: device_t(anetlist, name)
, m_params(*params)
, m_stat_calculations(*this, "m_stat_calculations", 0)
, m_stat_newton_raphson(*this, "m_stat_newton_raphson", 0)
, m_stat_vsolver_calls(*this, "m_stat_vsolver_calls", 0)
, m_iterative_fail(*this, "m_iterative_fail", 0)
, m_iterative_total(*this, "m_iterative_total", 0)
, m_last_step(*this, "m_last_step", netlist_time::zero())
, m_fb_sync(*this, "FB_sync")
, m_Q_sync(*this, "Q_sync")
, m_sort(sort)
{
connect_post_start(m_fb_sync, m_Q_sync);
}
const eSortType sort, const solver_parameters_t *params);
virtual ~matrix_solver_t();

View File

@ -59,509 +59,7 @@ namespace netlist
{
namespace devices
{
void terms_t::add(terminal_t *term, int net_other, bool sorted)
{
if (sorted)
for (unsigned i=0; i < m_net_other.size(); i++)
{
if (m_net_other[i] > net_other)
{
plib::container::insert_at(m_term, i, term);
plib::container::insert_at(m_net_other, i, net_other);
plib::container::insert_at(m_gt, i, 0.0);
plib::container::insert_at(m_go, i, 0.0);
plib::container::insert_at(m_Idr, i, 0.0);
plib::container::insert_at(m_other_curanalog, i, nullptr);
return;
}
}
m_term.push_back(term);
m_net_other.push_back(net_other);
m_gt.push_back(0.0);
m_go.push_back(0.0);
m_Idr.push_back(0.0);
m_other_curanalog.push_back(nullptr);
}
void terms_t::set_pointers()
{
for (unsigned i = 0; i < count(); i++)
{
m_term[i]->set_ptrs(&m_gt[i], &m_go[i], &m_Idr[i]);
m_other_curanalog[i] = m_term[i]->m_otherterm->net().m_cur_Analog.ptr();
}
}
// ----------------------------------------------------------------------------------------
// matrix_solver
// ----------------------------------------------------------------------------------------
matrix_solver_t::~matrix_solver_t()
{
for (unsigned k = 0; k < m_terms.size(); k++)
{
plib::pfree(m_terms[k]);
}
}
void matrix_solver_t::setup_base(analog_net_t::list_t &nets)
{
log().debug("New solver setup\n");
m_nets.clear();
m_terms.clear();
for (auto & net : nets)
{
m_nets.push_back(net);
m_terms.push_back(plib::palloc<terms_t>());
m_rails_temp.push_back(plib::palloc<terms_t>());
}
for (std::size_t k = 0; k < nets.size(); k++)
{
analog_net_t *net = nets[k];
log().debug("setting up net\n");
net->set_solver(this);
for (auto &p : net->m_core_terms)
{
log().debug("{1} {2} {3}\n", p->name(), net->name(), net->isRailNet());
switch (p->type())
{
case terminal_t::TERMINAL:
if (p->device().is_timestep())
if (!plib::container::contains(m_step_devices, &p->device()))
m_step_devices.push_back(&p->device());
if (p->device().is_dynamic())
if (!plib::container::contains(m_dynamic_devices, &p->device()))
m_dynamic_devices.push_back(&p->device());
{
terminal_t *pterm = dynamic_cast<terminal_t *>(p);
add_term(k, pterm);
}
log().debug("Added terminal {1}\n", p->name());
break;
case terminal_t::INPUT:
{
proxied_analog_output_t *net_proxy_output = nullptr;
for (auto & input : m_inps)
if (input->m_proxied_net == &p->net())
{
net_proxy_output = input.get();
break;
}
if (net_proxy_output == nullptr)
{
auto net_proxy_output_u = plib::make_unique<proxied_analog_output_t>(*this, this->name() + "." + plib::pfmt("m{1}")(m_inps.size()));
net_proxy_output = net_proxy_output_u.get();
m_inps.push_back(std::move(net_proxy_output_u));
nl_assert(p->net().is_analog());
net_proxy_output->m_proxied_net = static_cast<analog_net_t *>(&p->net());
}
net_proxy_output->net().add_terminal(*p);
// FIXME: repeated
net_proxy_output->net().rebuild_list();
log().debug("Added input\n");
}
break;
case terminal_t::OUTPUT:
case terminal_t::PARAM:
log().fatal("unhandled element found\n");
break;
}
}
log().debug("added net with {1} populated connections\n", net->m_core_terms.size());
}
/* now setup the matrix */
setup_matrix();
}
void matrix_solver_t::setup_matrix()
{
const std::size_t iN = m_nets.size();
for (std::size_t k = 0; k < iN; k++)
{
m_terms[k]->m_railstart = m_terms[k]->count();
for (std::size_t i = 0; i < m_rails_temp[k]->count(); i++)
this->m_terms[k]->add(m_rails_temp[k]->terms()[i], m_rails_temp[k]->net_other()[i], false);
m_rails_temp[k]->clear(); // no longer needed
m_terms[k]->set_pointers();
}
for (unsigned k = 0; k < iN; k++)
plib::pfree(m_rails_temp[k]); // no longer needed
m_rails_temp.clear();
/* Sort in descending order by number of connected matrix voltages.
* The idea is, that for Gauss-Seidel algo the first voltage computed
* depends on the greatest number of previous voltages thus taking into
* account the maximum amout of information.
*
* This actually improves performance on popeye slightly. Average
* GS computations reduce from 2.509 to 2.370
*
* Smallest to largest : 2.613
* Unsorted : 2.509
* Largest to smallest : 2.370
*
* Sorting as a general matrix pre-conditioning is mentioned in
* literature but I have found no articles about Gauss Seidel.
*
* For Gaussian Elimination however increasing order is better suited.
* FIXME: Even better would be to sort on elements right of the matrix diagonal.
*
*/
if (m_sort != NOSORT)
{
int sort_order = (m_sort == DESCENDING ? 1 : -1);
for (unsigned k = 0; k < iN - 1; k++)
for (unsigned i = k+1; i < iN; i++)
{
if ((static_cast<int>(m_terms[k]->m_railstart) - static_cast<int>(m_terms[i]->m_railstart)) * sort_order < 0)
{
std::swap(m_terms[i], m_terms[k]);
std::swap(m_nets[i], m_nets[k]);
}
}
for (unsigned k = 0; k < iN; k++)
{
int *other = m_terms[k]->net_other();
for (unsigned i = 0; i < m_terms[k]->count(); i++)
if (other[i] != -1)
other[i] = get_net_idx(&m_terms[k]->terms()[i]->m_otherterm->net());
}
}
/* create a list of non zero elements. */
for (unsigned k = 0; k < iN; k++)
{
terms_t * t = m_terms[k];
/* pretty brutal */
int *other = t->net_other();
t->m_nz.clear();
for (unsigned i = 0; i < t->m_railstart; i++)
if (!plib::container::contains(t->m_nz, static_cast<unsigned>(other[i])))
t->m_nz.push_back(static_cast<unsigned>(other[i]));
t->m_nz.push_back(k); // add diagonal
/* and sort */
std::sort(t->m_nz.begin(), t->m_nz.end());
}
/* create a list of non zero elements right of the diagonal
* These list anticipate the population of array elements by
* Gaussian elimination.
*/
for (unsigned k = 0; k < iN; k++)
{
terms_t * t = m_terms[k];
/* pretty brutal */
int *other = t->net_other();
if (k==0)
t->m_nzrd.clear();
else
{
t->m_nzrd = m_terms[k-1]->m_nzrd;
for (auto j = t->m_nzrd.begin(); j != t->m_nzrd.end(); )
{
if (*j < k + 1)
j = t->m_nzrd.erase(j);
else
++j;
}
}
for (unsigned i = 0; i < t->m_railstart; i++)
if (!plib::container::contains(t->m_nzrd, static_cast<unsigned>(other[i])) && other[i] >= static_cast<int>(k + 1))
t->m_nzrd.push_back(static_cast<unsigned>(other[i]));
/* and sort */
std::sort(t->m_nzrd.begin(), t->m_nzrd.end());
}
/* create a list of non zero elements below diagonal k
* This should reduce cache misses ...
*/
bool **touched = new bool*[iN];
for (unsigned k=0; k<iN; k++)
touched[k] = new bool[iN];
for (unsigned k = 0; k < iN; k++)
{
for (unsigned j = 0; j < iN; j++)
touched[k][j] = false;
for (unsigned j = 0; j < m_terms[k]->m_nz.size(); j++)
touched[k][m_terms[k]->m_nz[j]] = true;
}
unsigned ops = 0;
for (unsigned k = 0; k < iN; k++)
{
ops++; // 1/A(k,k)
for (unsigned row = k + 1; row < iN; row++)
{
if (touched[row][k])
{
ops++;
if (!plib::container::contains(m_terms[k]->m_nzbd, row))
m_terms[k]->m_nzbd.push_back(row);
for (unsigned col = k + 1; col < iN; col++)
if (touched[k][col])
{
touched[row][col] = true;
ops += 2;
}
}
}
}
log().verbose("Number of mults/adds for {1}: {2}", name(), ops);
if ((0))
for (unsigned k = 0; k < iN; k++)
{
pstring line = plib::pfmt("{1}")(k, "3");
for (unsigned j = 0; j < m_terms[k]->m_nzrd.size(); j++)
line += plib::pfmt(" {1}")(m_terms[k]->m_nzrd[j], "3");
log().verbose("{1}", line);
}
/*
* save states
*/
for (unsigned k = 0; k < iN; k++)
{
pstring num = plib::pfmt("{1}")(k);
netlist().save(*this, m_terms[k]->m_last_V, "lastV." + num);
netlist().save(*this, m_terms[k]->m_DD_n_m_1, "m_DD_n_m_1." + num);
netlist().save(*this, m_terms[k]->m_h_n_m_1, "m_h_n_m_1." + num);
netlist().save(*this, m_terms[k]->go(),"GO" + num, m_terms[k]->count());
netlist().save(*this, m_terms[k]->gt(),"GT" + num, m_terms[k]->count());
netlist().save(*this, m_terms[k]->Idr(),"IDR" + num , m_terms[k]->count());
}
for (unsigned k=0; k<iN; k++)
delete [] touched[k];
delete [] touched;
}
void matrix_solver_t::update_inputs()
{
// avoid recursive calls. Inputs are updated outside this call
for (auto &inp : m_inps)
inp->push(inp->m_proxied_net->Q_Analog());
}
void matrix_solver_t::update_dynamic()
{
/* update all non-linear devices */
for (auto &dyn : m_dynamic_devices)
dyn->update_terminals();
}
void matrix_solver_t::reset()
{
m_last_step = netlist_time::zero();
}
void matrix_solver_t::update() NL_NOEXCEPT
{
const netlist_time new_timestep = solve();
if (m_params.m_dynamic && has_timestep_devices() && new_timestep > netlist_time::zero())
{
m_Q_sync.net().force_queue_execution();
m_Q_sync.net().reschedule_in_queue(new_timestep);
}
}
void matrix_solver_t::update_forced()
{
ATTR_UNUSED const netlist_time new_timestep = solve();
if (m_params.m_dynamic && has_timestep_devices())
{
m_Q_sync.net().force_queue_execution();
m_Q_sync.net().reschedule_in_queue(netlist_time::from_double(m_params.m_min_timestep));
}
}
void matrix_solver_t::step(const netlist_time &delta)
{
const nl_double dd = delta.as_double();
for (std::size_t k=0; k < m_step_devices.size(); k++)
m_step_devices[k]->timestep(dd);
}
void matrix_solver_t::solve_base()
{
m_stat_vsolver_calls++;
if (has_dynamic_devices())
{
unsigned this_resched;
unsigned newton_loops = 0;
do
{
update_dynamic();
// Gauss-Seidel will revert to Gaussian elemination if steps exceeded.
this_resched = this->vsolve_non_dynamic(true);
newton_loops++;
} while (this_resched > 1 && newton_loops < m_params.m_nr_loops);
m_stat_newton_raphson += newton_loops;
// reschedule ....
if (this_resched > 1 && !m_Q_sync.net().is_queued())
{
log().warning("NEWTON_LOOPS exceeded on net {1}... reschedule", this->name());
m_Q_sync.net().toggle_new_Q();
m_Q_sync.net().reschedule_in_queue(m_params.m_nt_sync_delay);
}
}
else
{
this->vsolve_non_dynamic(false);
}
}
const netlist_time matrix_solver_t::solve()
{
const netlist_time now = netlist().time();
const netlist_time delta = now - m_last_step;
// We are already up to date. Avoid oscillations.
// FIXME: Make this a parameter!
if (delta < netlist_time::quantum())
return netlist_time::zero();
/* update all terminals for new time step */
m_last_step = now;
step(delta);
solve_base();
const netlist_time next_time_step = compute_next_timestep(delta.as_double());
update_inputs();
return next_time_step;
}
int matrix_solver_t::get_net_idx(detail::net_t *net)
{
for (std::size_t k = 0; k < m_nets.size(); k++)
if (m_nets[k] == net)
return static_cast<int>(k);
return -1;
}
void matrix_solver_t::add_term(std::size_t k, terminal_t *term)
{
if (term->m_otherterm->net().isRailNet())
{
m_rails_temp[k]->add(term, -1, false);
}
else
{
int ot = get_net_idx(&term->m_otherterm->net());
if (ot>=0)
{
m_terms[k]->add(term, ot, true);
}
/* Should this be allowed ? */
else // if (ot<0)
{
m_rails_temp[k]->add(term, ot, true);
log().fatal("found term with missing othernet {1}\n", term->name());
}
}
}
netlist_time matrix_solver_t::compute_next_timestep(const double cur_ts)
{
nl_double new_solver_timestep = m_params.m_max_timestep;
if (m_params.m_dynamic)
{
/*
* FIXME: We should extend the logic to use either all nets or
* only output nets.
*/
for (std::size_t k = 0, iN=m_terms.size(); k < iN; k++)
{
analog_net_t *n = m_nets[k];
terms_t *t = m_terms[k];
const nl_double DD_n = (n->Q_Analog() - t->m_last_V);
const nl_double hn = cur_ts;
//printf("%f %f %f %f\n", DD_n, t->m_DD_n_m_1, hn, t->m_h_n_m_1);
nl_double DD2 = (DD_n / hn - t->m_DD_n_m_1 / t->m_h_n_m_1) / (hn + t->m_h_n_m_1);
nl_double new_net_timestep;
t->m_h_n_m_1 = hn;
t->m_DD_n_m_1 = DD_n;
if (std::fabs(DD2) > NL_FCONST(1e-60)) // avoid div-by-zero
new_net_timestep = std::sqrt(m_params.m_lte / std::fabs(NL_FCONST(0.5)*DD2));
else
new_net_timestep = m_params.m_max_timestep;
if (new_net_timestep < new_solver_timestep)
new_solver_timestep = new_net_timestep;
t->m_last_V = n->Q_Analog();
}
if (new_solver_timestep < m_params.m_min_timestep)
{
//log().warning("Dynamic timestep below min timestep. Consider decreasing MIN_TIMESTEP: {1} us", new_solver_timestep*1.0e6);
new_solver_timestep = m_params.m_min_timestep;
}
}
//if (new_solver_timestep > 10.0 * hn)
// new_solver_timestep = 10.0 * hn;
/*
* FIXME: Factor 2 below is important. Without, we get timing issues. This must be a bug elsewhere.
*/
return std::max(netlist_time::from_double(new_solver_timestep), netlist_time::quantum() * 2);
}
void matrix_solver_t::log_stats()
{
if (this->m_stat_calculations != 0 && this->m_stat_vsolver_calls && this->m_params.m_log_stats)
{
log().verbose("==============================================");
log().verbose("Solver {1}", this->name());
log().verbose(" ==> {1} nets", this->m_nets.size()); //, (*(*groups[i].first())->m_core_terms.first())->name());
log().verbose(" has {1} elements", this->has_dynamic_devices() ? "dynamic" : "no dynamic");
log().verbose(" has {1} elements", this->has_timestep_devices() ? "timestep" : "no timestep");
log().verbose(" {1:6.3} average newton raphson loops",
static_cast<double>(this->m_stat_newton_raphson) / static_cast<double>(this->m_stat_vsolver_calls));
log().verbose(" {1:10} invocations ({2:6.0} Hz) {3:10} gs fails ({4:6.2} %) {5:6.3} average",
this->m_stat_calculations(),
static_cast<double>(this->m_stat_calculations()) / this->netlist().time().as_double(),
this->m_iterative_fail(),
100.0 * static_cast<double>(this->m_iterative_fail())
/ static_cast<double>(this->m_stat_calculations()),
static_cast<double>(this->m_iterative_total()) / static_cast<double>(this->m_stat_calculations()));
}
}
// ----------------------------------------------------------------------------------------

View File

@ -58,6 +58,19 @@ static lib_map_t read_lib_map(const pstring lm)
convert - convert a spice netlist
-------------------------------------------------*/
nl_convert_base_t::nl_convert_base_t()
: out(m_buf)
, m_numberchars("0123456789-+e.")
{
}
nl_convert_base_t::~nl_convert_base_t()
{
m_nets.clear();
m_devs.clear();
m_pins.clear();
}
void nl_convert_base_t::add_pin_alias(const pstring &devname, const pstring &name, const pstring &alias)
{
pstring pname = devname + "." + name;
@ -384,19 +397,53 @@ void nl_convert_spice_t::process_line(const pstring &line)
}
}
/*-------------------------------------------------
Eagle converter
-------------------------------------------------*/
nl_convert_eagle_t::tokenizer::tokenizer(nl_convert_eagle_t &convert, plib::pistream &strm)
: plib::ptokenizer(strm)
, m_convert(convert)
{
set_identifier_chars("abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-");
set_number_chars(".0123456789", "0123456789eE-."); //FIXME: processing of numbers
char ws[5];
ws[0] = ' ';
ws[1] = 9;
ws[2] = 10;
ws[3] = 13;
ws[4] = 0;
set_whitespace(ws);
/* FIXME: gnetlist doesn't print comments */
set_comment("/*", "*/", "//");
set_string_char('\'');
m_tok_ADD = register_token("ADD");
m_tok_VALUE = register_token("VALUE");
m_tok_SIGNAL = register_token("SIGNAL");
m_tok_SEMICOLON = register_token(";");
/* currently not used, but required for parsing */
register_token(")");
register_token("(");
}
void nl_convert_eagle_t::tokenizer::verror(const pstring &msg, int line_num, const pstring &line)
{
m_convert.out("{} (line {}): {}\n", msg.c_str(), line_num, line.c_str());
}
//FIXME: should accept a stream as well
void nl_convert_eagle_t::convert(const pstring &contents)
{
plib::pistringstream istrm(contents);
eagle_tokenizer tok(*this, istrm);
tokenizer tok(*this, istrm);
out("NETLIST_START(dummy)\n");
add_term("GND", "GND");
add_term("VCC", "VCC");
eagle_tokenizer::token_t token = tok.get_token();
tokenizer::token_t token = tok.get_token();
while (true)
{
if (token.is_type(eagle_tokenizer::ENDOFFILE))
if (token.is_type(tokenizer::ENDOFFILE))
{
dump_nl();
// FIXME: Parameter
@ -492,6 +539,42 @@ void nl_convert_eagle_t::convert(const pstring &contents)
}
/*-------------------------------------------------
RINF converter
-------------------------------------------------*/
nl_convert_rinf_t::tokenizer::tokenizer(nl_convert_rinf_t &convert, plib::pistream &strm)
: plib::ptokenizer(strm)
, m_convert(convert)
{
set_identifier_chars(".abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_-");
set_number_chars("0123456789", "0123456789eE-."); //FIXME: processing of numbers
char ws[5];
ws[0] = ' ';
ws[1] = 9;
ws[2] = 10;
ws[3] = 13;
ws[4] = 0;
set_whitespace(ws);
/* FIXME: gnetlist doesn't print comments */
set_comment("","","//"); // FIXME:needs to be confirmed
set_string_char('"');
m_tok_HEA = register_token(".HEA");
m_tok_APP = register_token(".APP");
m_tok_TIM = register_token(".TIM");
m_tok_TYP = register_token(".TYP");
m_tok_ADDC = register_token(".ADD_COM");
m_tok_ATTC = register_token(".ATT_COM");
m_tok_NET = register_token(".ADD_TER");
m_tok_TER = register_token(".TER");
m_tok_END = register_token(".END");
}
void nl_convert_rinf_t::tokenizer::verror(const pstring &msg, int line_num, const pstring &line)
{
m_convert.out("{} (line {}): {}\n", msg.c_str(), line_num, line.c_str());
}
/* token_id_t m_tok_HFA;
token_id_t m_tok_APP;
token_id_t m_tok_TIM;
@ -502,6 +585,7 @@ void nl_convert_eagle_t::convert(const pstring &contents)
token_id_t m_tok_TER;
*
*/
void nl_convert_rinf_t::convert(const pstring &contents)
{
plib::pistringstream istrm(contents);

View File

@ -23,13 +23,8 @@ class nl_convert_base_t
{
public:
nl_convert_base_t() : out(m_buf), m_numberchars("0123456789-+e.") {}
virtual ~nl_convert_base_t()
{
m_nets.clear();
m_devs.clear();
m_pins.clear();
}
nl_convert_base_t();
virtual ~nl_convert_base_t();
const pstringbuffer &result() { return m_buf.str(); }
@ -168,32 +163,10 @@ public:
{
}
class eagle_tokenizer : public plib::ptokenizer
class tokenizer : public plib::ptokenizer
{
public:
eagle_tokenizer(nl_convert_eagle_t &convert, plib::pistream &strm)
: plib::ptokenizer(strm), m_convert(convert)
{
set_identifier_chars("abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-");
set_number_chars(".0123456789", "0123456789eE-."); //FIXME: processing of numbers
char ws[5];
ws[0] = ' ';
ws[1] = 9;
ws[2] = 10;
ws[3] = 13;
ws[4] = 0;
set_whitespace(ws);
/* FIXME: gnetlist doesn't print comments */
set_comment("/*", "*/", "//");
set_string_char('\'');
m_tok_ADD = register_token("ADD");
m_tok_VALUE = register_token("VALUE");
m_tok_SIGNAL = register_token("SIGNAL");
m_tok_SEMICOLON = register_token(";");
/* currently not used, but required for parsing */
register_token(")");
register_token("(");
}
tokenizer(nl_convert_eagle_t &convert, plib::pistream &strm);
token_id_t m_tok_ADD;
token_id_t m_tok_VALUE;
@ -202,11 +175,7 @@ public:
protected:
void verror(const pstring &msg, int line_num, const pstring &line) override
{
m_convert.out("{} (line {}): {}\n", msg.c_str(), line_num, line.c_str());
}
virtual void verror(const pstring &msg, int line_num, const pstring &line) override;
private:
nl_convert_eagle_t &m_convert;
@ -233,31 +202,7 @@ public:
class tokenizer : public plib::ptokenizer
{
public:
tokenizer(nl_convert_rinf_t &convert, plib::pistream &strm)
: plib::ptokenizer(strm), m_convert(convert)
{
set_identifier_chars(".abcdefghijklmnopqrstuvwvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_-");
set_number_chars("0123456789", "0123456789eE-."); //FIXME: processing of numbers
char ws[5];
ws[0] = ' ';
ws[1] = 9;
ws[2] = 10;
ws[3] = 13;
ws[4] = 0;
set_whitespace(ws);
/* FIXME: gnetlist doesn't print comments */
set_comment("","","//"); // FIXME:needs to be confirmed
set_string_char('"');
m_tok_HEA = register_token(".HEA");
m_tok_APP = register_token(".APP");
m_tok_TIM = register_token(".TIM");
m_tok_TYP = register_token(".TYP");
m_tok_ADDC = register_token(".ADD_COM");
m_tok_ATTC = register_token(".ATT_COM");
m_tok_NET = register_token(".ADD_TER");
m_tok_TER = register_token(".TER");
m_tok_END = register_token(".END");
}
tokenizer(nl_convert_rinf_t &convert, plib::pistream &strm);
token_id_t m_tok_HEA;
token_id_t m_tok_APP;
@ -271,11 +216,7 @@ public:
protected:
void verror(const pstring &msg, int line_num, const pstring &line) override
{
m_convert.out("{} (line {}): {}\n", msg.c_str(), line_num, line.c_str());
}
virtual void verror(const pstring &msg, int line_num, const pstring &line) override;
private:
nl_convert_rinf_t &m_convert;