mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
Fix clang "-Wno-weak-vtables" warnings in netlist source. Refactored
code along the way. (nw)
This commit is contained in:
parent
67841056da
commit
02c3f45bff
@ -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",
|
||||
|
@ -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
|
||||
#
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
} }
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
562
src/lib/netlist/solver/nld_matrix_solver.cpp
Normal file
562
src/lib/netlist/solver/nld_matrix_solver.cpp
Normal 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
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user