mirror of
https://github.com/holub/mame
synced 2025-05-28 16:43:04 +03:00
Netlist maintenance:
- made frequency a obligatory parameter for CLOCK, MAINCLOCK and SOLVER - fixed a bad memory corruption. - added "owner" to save states. This allows to remove objects after they registered state. - fixed VCCS and VCVS.
This commit is contained in:
parent
f44b1831a6
commit
c7eee90411
@ -450,6 +450,7 @@ ATTR_COLD void netlist_mame_device_t::save_state()
|
||||
save_pointer((bool *) s->m_ptr, s->m_name, s->m_count);
|
||||
break;
|
||||
case DT_CUSTOM:
|
||||
break;
|
||||
case NOT_SUPPORTED:
|
||||
default:
|
||||
netlist().error("found unsupported save element %s\n", s->m_name.cstr());
|
||||
|
@ -12,44 +12,46 @@
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
NETLIB_START(VCCS)
|
||||
{
|
||||
configure(1.0, NETLIST_GMIN);
|
||||
}
|
||||
|
||||
NETLIB_RESET(VCCS)
|
||||
{
|
||||
}
|
||||
|
||||
ATTR_COLD void NETLIB_NAME(VCCS)::configure(const double Gfac, const double GI)
|
||||
{
|
||||
register_param("G", m_G, 1.0);
|
||||
register_param("RI", m_RI, 1.0 / NETLIST_GMIN);
|
||||
|
||||
register_terminal("IP", m_IP);
|
||||
register_terminal("IN", m_IN);
|
||||
register_terminal("OP", m_OP);
|
||||
register_terminal("ON", m_ON);
|
||||
|
||||
m_OP1.init_object(*this, name() + ".OP1");
|
||||
m_ON1.init_object(*this, name() + ".ON1");
|
||||
register_terminal("_OP1", m_OP1);
|
||||
register_terminal("_ON1", m_ON1);
|
||||
|
||||
const double m_mult = m_G.Value() * Gfac; // 1.0 ==> 1V ==> 1A
|
||||
m_IP.set(GI);
|
||||
m_IP.m_otherterm = &m_IN; // <= this should be NULL and terminal be filtered out prior to solving...
|
||||
m_IN.set(GI);
|
||||
m_IN.m_otherterm = &m_IP; // <= this should be NULL and terminal be filtered out prior to solving...
|
||||
|
||||
m_OP.set(m_mult, 0.0);
|
||||
m_OP.m_otherterm = &m_IP;
|
||||
m_OP1.set(-m_mult, 0.0);
|
||||
m_OP1.m_otherterm = &m_IN;
|
||||
|
||||
m_ON.set(-m_mult, 0.0);
|
||||
m_ON.m_otherterm = &m_IP;
|
||||
m_ON1.set(m_mult, 0.0);
|
||||
m_ON1.m_otherterm = &m_IN;
|
||||
|
||||
connect(m_OP, m_OP1);
|
||||
connect(m_ON, m_ON1);
|
||||
|
||||
m_gfac = 1.0;
|
||||
}
|
||||
|
||||
NETLIB_RESET(VCCS)
|
||||
{
|
||||
const double m_mult = m_G.Value() * m_gfac; // 1.0 ==> 1V ==> 1A
|
||||
const double GI = 1.0 / m_RI.Value();
|
||||
|
||||
m_IP.set(GI);
|
||||
m_IN.set(GI);
|
||||
|
||||
m_OP.set(m_mult, 0.0);
|
||||
m_OP1.set(-m_mult, 0.0);
|
||||
|
||||
m_ON.set(-m_mult, 0.0);
|
||||
m_ON1.set(m_mult, 0.0);
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAM(VCCS)
|
||||
@ -60,10 +62,14 @@ NETLIB_UPDATE(VCCS)
|
||||
{
|
||||
/* only called if connected to a rail net ==> notify the solver to recalculate */
|
||||
/* Big FIXME ... */
|
||||
m_IP.net().solve();
|
||||
m_IN.net().solve();
|
||||
m_OP.net().solve();
|
||||
m_ON.net().solve();
|
||||
if (!m_IP.net().isRailNet())
|
||||
m_IP.net().solve();
|
||||
else if (!m_IN.net().isRailNet())
|
||||
m_IN.net().solve();
|
||||
else if (!m_OP.net().isRailNet())
|
||||
m_OP.net().solve();
|
||||
else if (!m_ON.net().isRailNet())
|
||||
m_ON.net().solve();
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
@ -72,17 +78,13 @@ NETLIB_UPDATE(VCCS)
|
||||
|
||||
NETLIB_START(VCVS)
|
||||
{
|
||||
NETLIB_NAME(VCCS)::start();
|
||||
|
||||
register_param("RO", m_RO, 1.0);
|
||||
|
||||
const double gRO = 1.0 / m_RO.Value();
|
||||
register_terminal("_OP2", m_OP2);
|
||||
register_terminal("_ON2", m_ON2);
|
||||
|
||||
configure(gRO, NETLIST_GMIN);
|
||||
|
||||
m_OP2.init_object(*this, "OP2");
|
||||
m_ON2.init_object(*this, "ON2");
|
||||
|
||||
m_OP2.set(gRO);
|
||||
m_ON2.set(gRO);
|
||||
m_OP2.m_otherterm = &m_ON2;
|
||||
m_ON2.m_otherterm = &m_OP2;
|
||||
|
||||
@ -90,6 +92,15 @@ NETLIB_START(VCVS)
|
||||
connect(m_ON2, m_ON1);
|
||||
}
|
||||
|
||||
NETLIB_RESET(VCVS)
|
||||
{
|
||||
m_gfac = 1.0 / m_RO.Value();
|
||||
NETLIB_NAME(VCCS)::reset();
|
||||
|
||||
m_OP2.set(1.0 / m_RO.Value());
|
||||
m_ON2.set(1.0 / m_RO.Value());
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAM(VCVS)
|
||||
{
|
||||
}
|
||||
|
@ -83,8 +83,6 @@ protected:
|
||||
ATTR_COLD virtual void update_param();
|
||||
ATTR_HOT ATTR_ALIGN void update();
|
||||
|
||||
ATTR_COLD void configure(const double Gfac, const double GI);
|
||||
|
||||
netlist_terminal_t m_OP;
|
||||
netlist_terminal_t m_ON;
|
||||
|
||||
@ -95,6 +93,9 @@ protected:
|
||||
netlist_terminal_t m_ON1;
|
||||
|
||||
netlist_param_double_t m_G;
|
||||
netlist_param_double_t m_RI;
|
||||
|
||||
double m_gfac;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
@ -133,6 +134,7 @@ public:
|
||||
|
||||
protected:
|
||||
ATTR_COLD virtual void start();
|
||||
ATTR_COLD virtual void reset();
|
||||
ATTR_COLD virtual void update_param();
|
||||
//ATTR_HOT ATTR_ALIGN void update();
|
||||
|
||||
|
@ -19,9 +19,7 @@
|
||||
|
||||
ATTR_COLD void netlist_matrix_solver_t::setup(netlist_net_t::list_t &nets, NETLIB_NAME(solver) &aowner)
|
||||
{
|
||||
/* make sure we loop at least once */
|
||||
|
||||
m_owner = &aowner;
|
||||
m_owner = &aowner;
|
||||
|
||||
NL_VERBOSE_OUT(("New solver setup\n"));
|
||||
|
||||
@ -205,7 +203,10 @@ ATTR_COLD void netlist_matrix_solver_direct_t<m_N, _storage_N>::setup(netlist_ne
|
||||
m_terms[m_term_num].net_other = ot;
|
||||
m_terms[m_term_num].term = terms[i];
|
||||
if (ot>=0)
|
||||
{
|
||||
m_term_num++;
|
||||
SOLVER_VERBOSE_OUT(("Net %d Term %s %f %f\n", k, terms[i]->name().cstr(), terms[i]->m_gt, terms[i]->m_go));
|
||||
}
|
||||
}
|
||||
}
|
||||
m_rail_start = m_term_num;
|
||||
@ -221,7 +222,10 @@ ATTR_COLD void netlist_matrix_solver_direct_t<m_N, _storage_N>::setup(netlist_ne
|
||||
m_terms[m_term_num].net_other = ot;
|
||||
m_terms[m_term_num].term = terms[i];
|
||||
if (ot<0)
|
||||
{
|
||||
m_term_num++;
|
||||
SOLVER_VERBOSE_OUT(("found term with missing othernet %s\n", terms[i]->name().cstr()));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < rails.count(); i++)
|
||||
{
|
||||
@ -229,6 +233,7 @@ ATTR_COLD void netlist_matrix_solver_direct_t<m_N, _storage_N>::setup(netlist_ne
|
||||
m_terms[m_term_num].net_other = -1; //get_net_idx(&rails[i]->m_otherterm->net());
|
||||
m_terms[m_term_num].term = rails[i];
|
||||
m_term_num++;
|
||||
SOLVER_VERBOSE_OUT(("Net %d Rail %s %f %f\n", k, rails[i]->name().cstr(), rails[i]->m_gt, rails[i]->m_go));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -258,6 +263,7 @@ ATTR_HOT inline void netlist_matrix_solver_direct_t<m_N, _storage_N>::build_LE(
|
||||
for (int i = 0; i < m_rail_start; i++)
|
||||
{
|
||||
terms_t &t = m_terms[i];
|
||||
//printf("A %d %d %s %f %f\n",t.net_this, t.net_other, t.term->name().cstr(), t.term->m_gt, t.term->m_go);
|
||||
RHS[t.net_this] += t.term->m_Idr;
|
||||
A[t.net_this][t.net_this] += t.term->m_gt;
|
||||
|
||||
@ -280,6 +286,16 @@ ATTR_HOT inline void netlist_matrix_solver_direct_t<m_N, _storage_N>::gauss_LE(
|
||||
double (* RESTRICT RHS),
|
||||
double (* RESTRICT x))
|
||||
{
|
||||
#if 0
|
||||
for (int i = 0; i < N(); i++)
|
||||
{
|
||||
for (int k = 0; k < N(); k++)
|
||||
printf("%f ", A[i][k]);
|
||||
printf("| %f = %f \n", x[i], RHS[i]);
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < N(); i++) {
|
||||
|
||||
#if 0
|
||||
@ -322,8 +338,8 @@ ATTR_HOT inline void netlist_matrix_solver_direct_t<m_N, _storage_N>::gauss_LE(
|
||||
tmp += A[j][k] * x[k];
|
||||
x[j] = (RHS[j] - tmp) / A[j][j];
|
||||
}
|
||||
|
||||
#if 0
|
||||
printf("Solution:\n");
|
||||
for (int i = 0; i < N(); i++)
|
||||
{
|
||||
for (int k = 0; k < N(); k++)
|
||||
@ -332,6 +348,7 @@ ATTR_HOT inline void netlist_matrix_solver_direct_t<m_N, _storage_N>::gauss_LE(
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
template <int m_N, int _storage_N>
|
||||
@ -608,14 +625,14 @@ ATTR_COLD static void process_net(net_groups_t groups, int &cur_group, netlist_n
|
||||
if (net->m_head == NULL)
|
||||
return;
|
||||
/* add the net */
|
||||
NL_VERBOSE_OUT(("add %d - %s\n", cur_group, net->name().cstr()));
|
||||
SOLVER_VERBOSE_OUT(("add %d - %s\n", cur_group, net->name().cstr()));
|
||||
groups[cur_group].add(net);
|
||||
for (netlist_core_terminal_t *p = net->m_head; p != NULL; p = p->m_update_list_next)
|
||||
{
|
||||
NL_VERBOSE_OUT(("terminal %s\n", p->name().cstr()));
|
||||
SOLVER_VERBOSE_OUT(("terminal %s\n", p->name().cstr()));
|
||||
if (p->isType(netlist_terminal_t::TERMINAL))
|
||||
{
|
||||
NL_VERBOSE_OUT(("isterminal\n"));
|
||||
SOLVER_VERBOSE_OUT(("isterminal\n"));
|
||||
netlist_terminal_t *pt = static_cast<netlist_terminal_t *>(p);
|
||||
netlist_net_t *other_net = &pt->m_otherterm->net();
|
||||
if (!already_processed(groups, cur_group, other_net))
|
||||
@ -805,9 +822,18 @@ ATTR_COLD void NETLIB_NAME(solver)::post_start()
|
||||
ms->m_resched_loops = m_resched_loops.Value();
|
||||
ms->setup(groups[i], *this);
|
||||
m_mat_solvers.add(ms);
|
||||
SOLVER_VERBOSE_OUT(("%d ==> %d nets %s\n", i, groups[i].count(), groups[i].first()->object()->m_head->name().cstr()));
|
||||
SOLVER_VERBOSE_OUT(("%d ==> %d nets %s\n", i, groups[i].count(), (*groups[i].first())->m_head->name().cstr()));
|
||||
SOLVER_VERBOSE_OUT((" has %s elements\n", ms->is_dynamic() ? "dynamic" : "no dynamic"));
|
||||
SOLVER_VERBOSE_OUT((" has %s elements\n", ms->is_timestep() ? "timestep" : "no timestep"));
|
||||
for (int j=0; j<groups[i].count(); j++)
|
||||
{
|
||||
SOLVER_VERBOSE_OUT(("Net %d: %s\n", j, groups[i][j]->name().cstr()));
|
||||
netlist_net_t *n = groups[i][j];
|
||||
for (netlist_core_terminal_t *p = n->m_head; p != NULL; p = p->m_update_list_next)
|
||||
{
|
||||
SOLVER_VERBOSE_OUT((" %s\n", p->name().cstr()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,8 +13,9 @@
|
||||
// Macros
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
#define SOLVER(_name) \
|
||||
NET_REGISTER_DEV(solver, _name)
|
||||
#define SOLVER(_name, _freq) \
|
||||
NET_REGISTER_DEV(solver, _name) \
|
||||
PARAM(_name.FREQ, _freq)
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// solver
|
||||
|
@ -86,9 +86,9 @@ void netlist_factory_t::initialize()
|
||||
ENTRY(analog_input, ANALOG_INPUT, "IN")
|
||||
ENTRY(log, LOG, "+I")
|
||||
ENTRY(logD, LOGD, "+I,I2")
|
||||
ENTRY(clock, CLOCK, "-") // FIXME
|
||||
ENTRY(mainclock, MAINCLOCK, "-") // FIXME
|
||||
ENTRY(solver, SOLVER, "-") // FIXME
|
||||
ENTRY(clock, CLOCK, "FREQ")
|
||||
ENTRY(mainclock, MAINCLOCK, "FREQ")
|
||||
ENTRY(solver, SOLVER, "FREQ")
|
||||
ENTRY(gnd, NETDEV_GND, "-")
|
||||
ENTRY(switch2, SWITCH2, "+i1,i2")
|
||||
ENTRY(nicRSFF, NETDEV_RSFF, "+S,R")
|
||||
|
@ -18,20 +18,22 @@
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
#define TTL_INPUT(_name, _v) \
|
||||
NET_REGISTER_DEV(ttl_input, _name) \
|
||||
NET_REGISTER_DEV(ttl_input, _name) \
|
||||
PARAM(_name.IN, _v)
|
||||
|
||||
#define ANALOG_INPUT(_name, _v) \
|
||||
NET_REGISTER_DEV(analog_input, _name) \
|
||||
NET_REGISTER_DEV(analog_input, _name) \
|
||||
PARAM(_name.IN, _v)
|
||||
|
||||
#define MAINCLOCK(_name) \
|
||||
NET_REGISTER_DEV(mainclock, _name)
|
||||
#define MAINCLOCK(_name, _freq) \
|
||||
NET_REGISTER_DEV(mainclock, _name) \
|
||||
PARAM(_name.FREQ, _freq)
|
||||
|
||||
#define CLOCK(_name) \
|
||||
NET_REGISTER_DEV(clock, _name)
|
||||
#define CLOCK(_name, _freq) \
|
||||
NET_REGISTER_DEV(clock, _name) \
|
||||
PARAM(_name.FREQ, _freq)
|
||||
|
||||
#define NETDEV_GND() \
|
||||
#define NETDEV_GND() \
|
||||
NET_REGISTER_DEV(gnd, GND)
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
@ -34,9 +34,9 @@ netlist_queue_t::netlist_queue_t(netlist_base_t &nl)
|
||||
void netlist_queue_t::register_state(pstate_manager_t &manager, const pstring &module)
|
||||
{
|
||||
NL_VERBOSE_OUT(("register_state\n"));
|
||||
manager.save_item(m_qsize, module + "." + "qsize");
|
||||
manager.save_item(m_times, module + "." + "times");
|
||||
manager.save_item(&(m_name[0][0]), module + "." + "names", sizeof(m_name));
|
||||
manager.save_item(m_qsize, this, module + "." + "qsize");
|
||||
manager.save_item(m_times, this, module + "." + "times");
|
||||
manager.save_item(&(m_name[0][0]), this, module + "." + "names", sizeof(m_name));
|
||||
}
|
||||
|
||||
void netlist_queue_t::on_pre_save()
|
||||
@ -140,18 +140,18 @@ static void tagmap_free_entries(T &tm)
|
||||
|
||||
netlist_base_t::~netlist_base_t()
|
||||
{
|
||||
tagmap_free_entries<tagmap_devices_t>(m_devices);
|
||||
|
||||
netlist_net_t * const *p = m_nets.first();
|
||||
while (p != NULL)
|
||||
for (int i=0; i < m_nets.count(); i++)
|
||||
{
|
||||
netlist_net_t * const *pn = m_nets.next(p);
|
||||
if (!(*p)->isRailNet())
|
||||
delete (*p);
|
||||
p = pn;
|
||||
if (!m_nets[i]->isRailNet())
|
||||
{
|
||||
delete m_nets[i];
|
||||
}
|
||||
}
|
||||
|
||||
m_nets.reset();
|
||||
|
||||
tagmap_free_entries<tagmap_devices_t>(m_devices);
|
||||
|
||||
pstring::resetmem();
|
||||
}
|
||||
|
||||
@ -407,7 +407,6 @@ ATTR_COLD void netlist_device_t::register_output(const pstring &name, netlist_ou
|
||||
|
||||
ATTR_COLD void netlist_device_t::register_input(const pstring &name, netlist_input_t &inp)
|
||||
{
|
||||
// FIXME: change register_object as well
|
||||
inp.m_family_desc = this->m_family_desc;
|
||||
setup().register_object(*this, name, inp);
|
||||
m_terminals.add(inp.name());
|
||||
@ -425,7 +424,6 @@ ATTR_COLD void netlist_device_t::register_param(const pstring &sname, C ¶m,
|
||||
pstring fullname = this->name() + "." + sname;
|
||||
param.init_object(*this, fullname);
|
||||
param.initial(initialVal);
|
||||
//FIXME: pass fullname from above
|
||||
setup().register_object(*this, fullname, param);
|
||||
}
|
||||
|
||||
@ -456,6 +454,12 @@ ATTR_COLD netlist_net_t::netlist_net_t(const type_t atype, const family_t afamil
|
||||
m_cur.Analog = 0.0;
|
||||
};
|
||||
|
||||
ATTR_COLD netlist_net_t::~netlist_net_t()
|
||||
{
|
||||
netlist().remove_save_items(this);
|
||||
}
|
||||
|
||||
|
||||
ATTR_COLD void netlist_net_t::reset()
|
||||
{
|
||||
m_last.Analog = 0.0;
|
||||
|
@ -62,7 +62,6 @@
|
||||
* This would however introduce macro devices for RC, diodes and transistors again.
|
||||
*
|
||||
* ====================================================================================
|
||||
* FIXME: Terminals are not yet implemented.
|
||||
*
|
||||
* Instead, the following approach in case of a pure terminal/input network is taken:
|
||||
*
|
||||
@ -557,7 +556,6 @@ public:
|
||||
friend class netlist_analog_output_t;
|
||||
friend class netlist_setup_t;
|
||||
|
||||
// FIXME: union does not work
|
||||
struct hybrid_t
|
||||
{
|
||||
inline hybrid_t() : Q(0), Analog(0.0) {}
|
||||
@ -566,6 +564,8 @@ public:
|
||||
};
|
||||
|
||||
ATTR_COLD netlist_net_t(const type_t atype, const family_t afamily);
|
||||
ATTR_COLD virtual ~netlist_net_t();
|
||||
|
||||
ATTR_COLD void init_object(netlist_base_t &nl, const pstring &aname);
|
||||
|
||||
ATTR_COLD void register_con(netlist_core_terminal_t &terminal);
|
||||
@ -638,28 +638,13 @@ public:
|
||||
typedef netlist_list_t<netlist_terminal_t *> terminal_list_t;
|
||||
|
||||
terminal_list_t m_terms;
|
||||
terminal_list_t m_rails; // FIXME: Make the solver use this !
|
||||
terminal_list_t m_rails;
|
||||
netlist_matrix_solver_t *m_solver;
|
||||
|
||||
ATTR_HOT void solve();
|
||||
|
||||
netlist_core_terminal_t *m_head;
|
||||
|
||||
/* use this to register state.... */
|
||||
ATTR_COLD virtual void late_save_register()
|
||||
{
|
||||
save(NAME(m_last.Analog));
|
||||
save(NAME(m_cur.Analog));
|
||||
save(NAME(m_new.Analog));
|
||||
save(NAME(m_last.Q));
|
||||
save(NAME(m_cur.Q));
|
||||
save(NAME(m_new.Q));
|
||||
save(NAME(m_time));
|
||||
save(NAME(m_active));
|
||||
save(NAME(m_in_queue));
|
||||
netlist_object_t::save_register();
|
||||
}
|
||||
|
||||
protected: //FIXME: needed by current solver code
|
||||
|
||||
UINT32 m_num_cons;
|
||||
@ -671,13 +656,18 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
/* we don't use this to save state
|
||||
* because we may get deleted again ...
|
||||
* FIXME: save_register should be called after setup is complete
|
||||
*/
|
||||
ATTR_COLD virtual void save_register()
|
||||
{
|
||||
//assert_always(false, "trying too early to register state in netlist_net_t");
|
||||
save(NAME(m_last.Analog));
|
||||
save(NAME(m_cur.Analog));
|
||||
save(NAME(m_new.Analog));
|
||||
save(NAME(m_last.Q));
|
||||
save(NAME(m_cur.Q));
|
||||
save(NAME(m_new.Q));
|
||||
save(NAME(m_time));
|
||||
save(NAME(m_active));
|
||||
save(NAME(m_in_queue));
|
||||
netlist_object_t::save_register();
|
||||
}
|
||||
ATTR_COLD virtual void reset();
|
||||
|
||||
@ -1235,7 +1225,6 @@ ATTR_HOT inline void netlist_net_t::push_to_queue(const netlist_time delay)
|
||||
{
|
||||
if (is_queued())
|
||||
return;
|
||||
// if (m_in_queue == 1) return; FIXME: check this at some time
|
||||
m_time = netlist().time() + delay;
|
||||
m_in_queue = (m_active > 0) ? 1 : 0; /* queued ? */
|
||||
if (m_in_queue)
|
||||
|
@ -270,22 +270,6 @@ const pstring netlist_setup_t::resolve_alias(const pstring &name) const
|
||||
temp = m_alias.find(ret);
|
||||
} while (temp != "");
|
||||
|
||||
int p = ret.find(".[");
|
||||
if (p > 0)
|
||||
{
|
||||
pstring dname = ret;
|
||||
netlist_device_t *dev = netlist().m_devices.find(dname.substr(0,p));
|
||||
if (dev == NULL)
|
||||
netlist().error("Device for %s not found\n", name.cstr());
|
||||
int c = atoi(ret.substr(p+2,ret.len()-p-3));
|
||||
temp = dev->m_terminals[c];
|
||||
// reresolve ....
|
||||
do {
|
||||
ret = temp;
|
||||
temp = m_alias.find(ret);
|
||||
} while (temp != "");
|
||||
}
|
||||
|
||||
NL_VERBOSE_OUT(("%s==>%s\n", name.cstr(), ret.cstr()));
|
||||
return ret;
|
||||
}
|
||||
@ -447,7 +431,6 @@ void netlist_setup_t::connect_terminal_input(netlist_terminal_t &term, netlist_i
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: optimize code ...
|
||||
void netlist_setup_t::connect_terminal_output(netlist_terminal_t &in, netlist_output_t &out)
|
||||
{
|
||||
if (out.isFamily(netlist_terminal_t::ANALOG))
|
||||
@ -521,18 +504,16 @@ void netlist_setup_t::connect(netlist_core_terminal_t &t1_in, netlist_core_termi
|
||||
netlist_core_terminal_t &t1 = resolve_proxy(t1_in);
|
||||
netlist_core_terminal_t &t2 = resolve_proxy(t2_in);
|
||||
|
||||
// FIXME: amend device design so that warnings can be turned into errors
|
||||
// Only variable inputs have this issue
|
||||
if (t1.isType(netlist_core_terminal_t::OUTPUT) && t2.isType(netlist_core_terminal_t::INPUT))
|
||||
{
|
||||
if (t2.has_net())
|
||||
NL_VERBOSE_OUT(("Input %s already connected\n", t2.name().cstr()));
|
||||
netlist().error("Input %s already connected\n", t2.name().cstr());
|
||||
connect_input_output(dynamic_cast<netlist_input_t &>(t2), dynamic_cast<netlist_output_t &>(t1));
|
||||
}
|
||||
else if (t1.isType(netlist_core_terminal_t::INPUT) && t2.isType(netlist_core_terminal_t::OUTPUT))
|
||||
{
|
||||
if (t1.has_net())
|
||||
NL_VERBOSE_OUT(("Input %s already connected\n", t1.name().cstr()));
|
||||
netlist().error("Input %s already connected\n", t1.name().cstr());
|
||||
connect_input_output(dynamic_cast<netlist_input_t &>(t1), dynamic_cast<netlist_output_t &>(t2));
|
||||
}
|
||||
else if (t1.isType(netlist_core_terminal_t::OUTPUT) && t2.isType(netlist_core_terminal_t::TERMINAL))
|
||||
@ -585,24 +566,24 @@ void netlist_setup_t::resolve_inputs()
|
||||
netlist().log("deleting empty nets ...");
|
||||
|
||||
// delete empty nets ...
|
||||
|
||||
netlist_net_t::list_t todelete;
|
||||
|
||||
for (netlist_net_t *const *pn = netlist().m_nets.first(); pn != NULL; pn = netlist().m_nets.next(pn))
|
||||
{
|
||||
if ((*pn)->m_head == NULL)
|
||||
{
|
||||
netlist().log("Deleting net %s ...", (*pn)->name().cstr());
|
||||
netlist_net_t *to_delete = *pn;
|
||||
netlist().m_nets.remove(to_delete);
|
||||
if (!to_delete->isRailNet())
|
||||
delete to_delete;
|
||||
pn--;
|
||||
todelete.add(*pn);
|
||||
}
|
||||
}
|
||||
|
||||
/* now that nets were deleted ... register all net items */
|
||||
netlist().log("late state saving for nets ...");
|
||||
|
||||
for (netlist_net_t * const * pn = netlist().m_nets.first(); pn != NULL; pn = netlist().m_nets.next(pn))
|
||||
(*pn)->late_save_register();
|
||||
for (int i=0; i < todelete.count(); i++)
|
||||
{
|
||||
netlist().log("Deleting net %s ...", todelete[i]->name().cstr());
|
||||
netlist().m_nets.remove(todelete[i]);
|
||||
if (!todelete[i]->isRailNet())
|
||||
delete todelete[i];
|
||||
}
|
||||
|
||||
pstring errstr("");
|
||||
|
||||
|
@ -12,7 +12,7 @@ ATTR_COLD pstate_manager_t::~pstate_manager_t()
|
||||
|
||||
|
||||
|
||||
ATTR_COLD void pstate_manager_t::save_state_ptr(const pstring &stname, const pstate_data_type_e dt, const int size, const int count, void *ptr)
|
||||
ATTR_COLD void pstate_manager_t::save_state_ptr(const pstring &stname, const pstate_data_type_e dt, const void *owner, const int size, const int count, void *ptr)
|
||||
{
|
||||
pstring fullname = stname;
|
||||
ATTR_UNUSED pstring ts[] = {
|
||||
@ -25,19 +25,36 @@ ATTR_COLD void pstate_manager_t::save_state_ptr(const pstring &stname, const pst
|
||||
};
|
||||
|
||||
NL_VERBOSE_OUT(("SAVE: <%s> %s(%d) %p\n", fullname.cstr(), ts[dt].cstr(), size, ptr));
|
||||
pstate_entry_t *p = new pstate_entry_t(stname, dt, size, count, ptr);
|
||||
pstate_entry_t *p = new pstate_entry_t(stname, dt, owner, size, count, ptr);
|
||||
m_save.add(p);
|
||||
}
|
||||
|
||||
ATTR_COLD void pstate_manager_t::remove_save_items(const void *owner)
|
||||
{
|
||||
pstate_entry_t::list_t todelete;
|
||||
|
||||
for (int i=0; i < m_save.count(); i++)
|
||||
{
|
||||
if (m_save[i]->m_owner == owner)
|
||||
todelete.add(m_save[i]);
|
||||
}
|
||||
for (int i=0; i < todelete.count(); i++)
|
||||
{
|
||||
m_save.remove(todelete[i]);
|
||||
}
|
||||
todelete.reset_and_free();
|
||||
}
|
||||
|
||||
ATTR_COLD void pstate_manager_t::pre_save()
|
||||
{
|
||||
for (int i=0; i < m_callback.count(); i++)
|
||||
m_callback[i]->on_pre_save();
|
||||
for (int i=0; i < m_save.count(); i++)
|
||||
if (m_save[i]->m_dt == DT_CUSTOM)
|
||||
m_save[i]->m_callback->on_pre_save();
|
||||
}
|
||||
|
||||
ATTR_COLD void pstate_manager_t::post_load()
|
||||
{
|
||||
for (int i=0; i < m_callback.count(); i++)
|
||||
m_callback[i]->on_post_load();
|
||||
for (int i=0; i < m_save.count(); i++)
|
||||
if (m_save[i]->m_dt == DT_CUSTOM)
|
||||
m_save[i]->m_callback->on_post_load();
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
#define PSTATE_INTERFACE(obj, manager, module) \
|
||||
template<typename C> ATTR_COLD void obj::save(C &state, const pstring &stname) \
|
||||
{ \
|
||||
manager->save_item(state, module + "." + stname); \
|
||||
manager->save_item(state, this, module + "." + stname); \
|
||||
}
|
||||
|
||||
enum pstate_data_type_e {
|
||||
@ -50,19 +50,6 @@ NETLIST_SAVE_TYPE(UINT32, DT_INT);
|
||||
NETLIST_SAVE_TYPE(INT32, DT_INT);
|
||||
//NETLIST_SAVE_TYPE(netlist_time::INTERNALTYPE, DT_INT64);
|
||||
|
||||
struct pstate_entry_t
|
||||
{
|
||||
typedef netlist_list_t<pstate_entry_t *> list_t;
|
||||
|
||||
pstate_entry_t(const pstring &stname, const pstate_data_type_e dt, const int size, const int count, void *ptr) :
|
||||
m_name(stname), m_dt(dt), m_size(size), m_count(count), m_ptr(ptr) { }
|
||||
pstring m_name;
|
||||
pstate_data_type_e m_dt;
|
||||
int m_size;
|
||||
int m_count;
|
||||
void *m_ptr;
|
||||
};
|
||||
|
||||
class pstate_manager_t;
|
||||
|
||||
class pstate_callback_t
|
||||
@ -78,50 +65,71 @@ public:
|
||||
protected:
|
||||
};
|
||||
|
||||
struct pstate_entry_t
|
||||
{
|
||||
typedef netlist_list_t<pstate_entry_t *> list_t;
|
||||
|
||||
pstate_entry_t(const pstring &stname, const pstate_data_type_e dt, const void *owner,
|
||||
const int size, const int count, void *ptr)
|
||||
: m_name(stname), m_dt(dt), m_owner(owner), m_callback(NULL), m_size(size), m_count(count), m_ptr(ptr) { }
|
||||
|
||||
pstate_entry_t(const pstring &stname, const void *owner, pstate_callback_t *callback)
|
||||
: m_name(stname), m_dt(DT_CUSTOM), m_owner(owner), m_callback(callback), m_size(0), m_count(0), m_ptr(NULL) { }
|
||||
|
||||
pstring m_name;
|
||||
const pstate_data_type_e m_dt;
|
||||
const void *m_owner;
|
||||
pstate_callback_t *m_callback;
|
||||
const int m_size;
|
||||
const int m_count;
|
||||
void *m_ptr;
|
||||
};
|
||||
|
||||
class pstate_manager_t
|
||||
{
|
||||
public:
|
||||
|
||||
ATTR_COLD ~pstate_manager_t();
|
||||
|
||||
template<typename C> ATTR_COLD void save_item(C &state, const pstring &stname)
|
||||
template<typename C> ATTR_COLD void save_item(C &state, const void *owner, const pstring &stname)
|
||||
{
|
||||
save_state_ptr(stname, nl_datatype<C>::type, sizeof(C), 1, &state);
|
||||
save_state_ptr(stname, nl_datatype<C>::type, owner, sizeof(C), 1, &state);
|
||||
}
|
||||
|
||||
template<typename C, std::size_t N> ATTR_COLD void save_item(C (&state)[N], const pstring &stname)
|
||||
template<typename C, std::size_t N> ATTR_COLD void save_item(C (&state)[N], const void *owner, const pstring &stname)
|
||||
{
|
||||
save_state_ptr(stname, nl_datatype<C>::type, sizeof(state[0]), N, &(state[0]));
|
||||
save_state_ptr(stname, nl_datatype<C>::type, owner, sizeof(state[0]), N, &(state[0]));
|
||||
}
|
||||
|
||||
template<typename C> ATTR_COLD void save_item(C *state, const pstring &stname, const int count)
|
||||
template<typename C> ATTR_COLD void save_item(C *state, const void *owner, const pstring &stname, const int count)
|
||||
{
|
||||
save_state_ptr(stname, nl_datatype<C>::type, sizeof(C), count, state);
|
||||
save_state_ptr(stname, nl_datatype<C>::type, owner, sizeof(C), count, state);
|
||||
}
|
||||
|
||||
ATTR_COLD void pre_save();
|
||||
ATTR_COLD void post_load();
|
||||
ATTR_COLD void remove_save_items(const void *owner);
|
||||
|
||||
inline const pstate_entry_t::list_t &save_list() const { return m_save; }
|
||||
|
||||
protected:
|
||||
ATTR_COLD void save_state_ptr(const pstring &stname, const pstate_data_type_e, const int size, const int count, void *ptr);
|
||||
ATTR_COLD void save_state_ptr(const pstring &stname, const pstate_data_type_e, const void *owner, const int size, const int count, void *ptr);
|
||||
|
||||
private:
|
||||
pstate_entry_t::list_t m_save;
|
||||
pstate_callback_t::list_t m_callback;
|
||||
};
|
||||
|
||||
template<> ATTR_COLD inline void pstate_manager_t::save_item(pstate_callback_t &state, const pstring &stname)
|
||||
template<> ATTR_COLD inline void pstate_manager_t::save_item(pstate_callback_t &state, const void *owner, const pstring &stname)
|
||||
{
|
||||
//save_state_ptr(stname, DT_CUSTOM, 0, 1, &state);
|
||||
m_callback.add(&state);
|
||||
pstate_entry_t *p = new pstate_entry_t(stname, owner, &state);
|
||||
m_save.add(p);
|
||||
state.register_state(*this, stname);
|
||||
}
|
||||
|
||||
template<> ATTR_COLD inline void pstate_manager_t::save_item(netlist_time &nlt, const pstring &stname)
|
||||
template<> ATTR_COLD inline void pstate_manager_t::save_item(netlist_time &nlt, const void *owner, const pstring &stname)
|
||||
{
|
||||
save_state_ptr(stname, DT_INT64, sizeof(netlist_time::INTERNALTYPE), 1, nlt.get_internaltype_ptr());
|
||||
save_state_ptr(stname, DT_INT64, owner, sizeof(netlist_time::INTERNALTYPE), 1, nlt.get_internaltype_ptr());
|
||||
}
|
||||
|
||||
|
||||
|
@ -82,8 +82,7 @@ static NETLIST_START(nl_1942)
|
||||
|
||||
/* Standard stuff */
|
||||
|
||||
SOLVER(Solver)
|
||||
PARAM(Solver.FREQ, 48000)
|
||||
SOLVER(Solver, 48000)
|
||||
ANALOG_INPUT(V5, 5)
|
||||
|
||||
/* AY 8910 internal resistors */
|
||||
|
@ -94,8 +94,7 @@ enum input_changed_enum
|
||||
|
||||
|
||||
static NETLIST_START(pong_schematics)
|
||||
SOLVER(Solver)
|
||||
PARAM(Solver.FREQ, 48000)
|
||||
SOLVER(Solver, 48000)
|
||||
PARAM(Solver.ACCURACY, 1e-4) // works and is sufficient
|
||||
|
||||
ANALOG_INPUT(V5, 5)
|
||||
@ -114,9 +113,8 @@ static NETLIST_START(pong_schematics)
|
||||
#else
|
||||
/* abstracting this, performance increases by 40%
|
||||
* No surprise, the clock is extremely expensive */
|
||||
MAINCLOCK(clk)
|
||||
//CLOCK(clk)
|
||||
PARAM(clk.FREQ, 7159000.0)
|
||||
MAINCLOCK(clk, 7159000.0)
|
||||
//CLOCK(clk, 7159000.0)
|
||||
#endif
|
||||
#else
|
||||
// benchmarking ...
|
||||
|
Loading…
Reference in New Issue
Block a user