diff options
author | Couriersud <couriersud@users.noreply.github.com> | 2013-11-04 20:47:32 +0000 |
---|---|---|
committer | Couriersud <couriersud@users.noreply.github.com> | 2013-11-04 20:47:32 +0000 |
commit | bf1909932338a67c257f7eb613c78d65b5c74a73 (patch) | |
tree | 54f4d62d5cfddd946d1071b7e859bebc29c17498 | |
parent | 39dc549a5f40b1495fb8a2bc5b1012db5e6b4e68 (diff) |
Split the netlist code up into functional pieces like parser, setup and execution. This looks a lot more structured now and highlighted some issue already.
-rw-r--r-- | .gitattributes | 17 | ||||
-rw-r--r-- | src/emu/emu.mak | 1 | ||||
-rw-r--r-- | src/emu/machine/netlist.c | 1060 | ||||
-rw-r--r-- | src/emu/machine/netlist.h | 1370 | ||||
-rw-r--r-- | src/emu/netlist/devices/net_lib.c (renamed from src/emu/netlist/net_lib.c) | 30 | ||||
-rw-r--r-- | src/emu/netlist/devices/net_lib.h (renamed from src/emu/netlist/net_lib.h) | 112 | ||||
-rw-r--r-- | src/emu/netlist/devices/nld_7400.c | 6 | ||||
-rw-r--r-- | src/emu/netlist/devices/nld_7400.h | 44 | ||||
-rw-r--r-- | src/emu/netlist/devices/nld_signal.h | 296 | ||||
-rw-r--r-- | src/emu/netlist/devices/nld_system.h | 82 | ||||
-rw-r--r-- | src/emu/netlist/netlist.mak | 8 | ||||
-rw-r--r-- | src/emu/netlist/nl_base.c | 435 | ||||
-rw-r--r-- | src/emu/netlist/nl_base.h | 811 | ||||
-rw-r--r-- | src/emu/netlist/nl_config.h | 103 | ||||
-rw-r--r-- | src/emu/netlist/nl_lists.h | 134 | ||||
-rw-r--r-- | src/emu/netlist/nl_parser.c | 207 | ||||
-rw-r--r-- | src/emu/netlist/nl_parser.h | 39 | ||||
-rw-r--r-- | src/emu/netlist/nl_setup.c | 318 | ||||
-rw-r--r-- | src/emu/netlist/nl_setup.h | 113 | ||||
-rw-r--r-- | src/emu/netlist/nl_time.h | 99 | ||||
-rw-r--r-- | src/mame/drivers/pong.c | 6 |
21 files changed, 2800 insertions, 2491 deletions
diff --git a/.gitattributes b/.gitattributes index 3e5b654e3d5..1d703b48d56 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2098,9 +2098,22 @@ src/emu/memarray.c svneol=native#text/plain src/emu/memarray.h svneol=native#text/plain src/emu/memory.c svneol=native#text/plain src/emu/memory.h svneol=native#text/plain -src/emu/netlist/net_lib.c svneol=native#text/plain -src/emu/netlist/net_lib.h svneol=native#text/plain +src/emu/netlist/devices/net_lib.c svneol=native#text/plain +src/emu/netlist/devices/net_lib.h svneol=native#text/plain +src/emu/netlist/devices/nld_7400.c svneol=native#text/plain +src/emu/netlist/devices/nld_7400.h svneol=native#text/plain +src/emu/netlist/devices/nld_signal.h svneol=native#text/plain +src/emu/netlist/devices/nld_system.h svneol=native#text/plain src/emu/netlist/netlist.mak svneol=native#text/plain +src/emu/netlist/nl_base.c svneol=native#text/plain +src/emu/netlist/nl_base.h svneol=native#text/plain +src/emu/netlist/nl_config.h svneol=native#text/plain +src/emu/netlist/nl_lists.h svneol=native#text/plain +src/emu/netlist/nl_parser.c svneol=native#text/plain +src/emu/netlist/nl_parser.h svneol=native#text/plain +src/emu/netlist/nl_setup.c svneol=native#text/plain +src/emu/netlist/nl_setup.h svneol=native#text/plain +src/emu/netlist/nl_time.h svneol=native#text/plain src/emu/network.c svneol=native#text/plain src/emu/network.h svneol=native#text/plain src/emu/output.c svneol=native#text/plain diff --git a/src/emu/emu.mak b/src/emu/emu.mak index 9abac43e3b1..c867a8d898d 100644 --- a/src/emu/emu.mak +++ b/src/emu/emu.mak @@ -60,6 +60,7 @@ OBJDIRS += \ $(EMUOBJ)/drivers \ $(EMUOBJ)/machine \ $(EMUOBJ)/netlist \ + $(EMUOBJ)/netlist/devices \ $(EMUOBJ)/layout \ $(EMUOBJ)/imagedev \ $(EMUOBJ)/video \ diff --git a/src/emu/machine/netlist.c b/src/emu/machine/netlist.c index 8dc6bfeeb03..d8fe4c0e7f5 100644 --- a/src/emu/machine/netlist.c +++ b/src/emu/machine/netlist.c @@ -45,1058 +45,13 @@ ****************************************************************************/ #include "netlist.h" -#include "netlist/net_lib.h" - -//============================================================ -// DEBUGGING -//============================================================ - -#define VERBOSE (0) -#define KEEP_STATISTICS (0) -#define FATAL_ERROR_AFTER_NS (0) //(1000) - -#if (VERBOSE) - #define VERBOSE_OUT(x) printf x -#else - #define VERBOSE_OUT(x) -#endif - -//============================================================ -// MACROS -//============================================================ - -#if KEEP_STATISTICS -#define add_to_stat(v,x) do { v += (x); } while (0) -#define inc_stat(v) add_to_stat(v, 1) -#define begin_timing(v) do { (v) -= get_profile_ticks(); } while (0) -#define end_timing(v) do { (v) += get_profile_ticks(); } while (0) -#else -#define add_to_stat(v,x) do { } while (0) -#define inc_stat(v) add_to_stat(v, 1) -#define begin_timing(v) do { } while (0) -#define end_timing(v) do { } while (0) -#endif +#include "netlist/nl_base.h" +#include "netlist/nl_setup.h" +#include "netlist/devices/net_lib.h" const netlist_time netlist_time::zero = netlist_time::from_raw(0); // ---------------------------------------------------------------------------------------- -// A netlist parser -// ---------------------------------------------------------------------------------------- - -class netlist_parser -{ -public: - netlist_parser(netlist_setup_t &setup) - : m_setup(setup) {} - - void parse(char *buf) - { - m_p = buf; - while (*m_p) - { - astring n; - skipws(); - if (!*m_p) break; - n = getname('('); - VERBOSE_OUT(("Parser: Device: %s\n", n.cstr())); - if (n == "NET_ALIAS") - net_alias(); - else if (n == "NETDEV_PARAM") - netdev_param(); - else if ((n == "NETDEV_TTL_CONST") || (n == "NETDEV_ANALOG_CONST")) - netdev_const(n); - else - netdev_device(n); - } - } - - void net_alias() - { - astring alias; - astring out; - skipws(); - alias = getname(','); - skipws(); - out = getname(')'); - VERBOSE_OUT(("Parser: Alias: %s %s\n", alias.cstr(), out.cstr())); - m_setup.register_alias(alias, out); - } - - void netdev_param() - { - astring param; - double val; - skipws(); - param = getname(','); - skipws(); - val = eval_param(); - VERBOSE_OUT(("Parser: Param: %s %f\n", param.cstr(), val)); - m_setup.find_param(param).initial(val); - check_char(')'); - } - - void netdev_const(const astring &dev_name) - { - astring name; - net_device_t *dev; - astring paramfq; - double val; - - skipws(); - name = getname(','); - dev = net_create_device_by_name(dev_name, m_setup, name); - m_setup.register_dev(dev); - skipws(); - val = eval_param(); - check_char(')'); - paramfq = name; - paramfq.cat(".CONST"); - VERBOSE_OUT(("Parser: Const: %s %f\n", name.cstr(), val)); - m_setup.find_param(paramfq).initial(val); - } - - void netdev_device(const astring &dev_type) - { - astring devname; - net_device_t *dev; - int cnt; - - skipws(); - devname = getname2(',', ')'); - dev = net_create_device_by_name(dev_type, m_setup, devname); - m_setup.register_dev(dev); - skipws(); - VERBOSE_OUT(("Parser: IC: %s\n", devname.cstr())); - cnt = 0; - while (*m_p != ')') - { - m_p++; - skipws(); - astring output_name = getname2(',', ')'); - VERBOSE_OUT(("Parser: ID: %s %s\n", output_name.cstr(), dev->m_inputs.item(cnt)->cstr())); - m_setup.register_link(*dev->m_inputs.item(cnt), output_name); - skipws(); - cnt++; - } - if (cnt != dev->m_inputs.count() && !dev->variable_input_count()) - fatalerror("netlist: input count mismatch for %s - expected %d found %d\n", devname.cstr(), dev->m_inputs.count(), cnt); - if (dev->variable_input_count()) - { - VERBOSE_OUT(("variable inputs %s: %d\n", dev->name().cstr(), cnt)); - } - check_char(')'); - } - -private: - - void skipeol() - { - while (*m_p) - { - if (*m_p == 10) - { - m_p++; - if (*m_p && *m_p == 13) - m_p++; - return; - } - m_p++; - } - } - - void skipws() - { - while (*m_p) - { - switch (*m_p) - { - case ' ': - case 9: - case 10: - case 13: - m_p++; - break; - case '/': - if (*(m_p+1) == '/') - skipeol(); - break; - default: - return; - } - } - } - - astring getname(char sep) - { - char buf[300]; - char *p1 = buf; - - while (*m_p != sep) - *p1++ = *m_p++; - *p1 = 0; - m_p++; - return astring(buf); - } - - astring getname2(char sep1, char sep2) - { - char buf[300]; - char *p1 = buf; - - while ((*m_p != sep1) && (*m_p != sep2)) - *p1++ = *m_p++; - *p1 = 0; - return astring(buf); - } - - void check_char(char ctocheck) - { - skipws(); - if (*m_p == ctocheck) - { - m_p++; - return; - } - fatalerror("Parser: expected '%c' found '%c'\n", ctocheck, *m_p); - } - - double eval_param() - { - static const char *macs[6] = {"", "RES_K(", "RES_M(", "CAP_U(", "CAP_N(", "CAP_P("}; - static double facs[6] = {1, 1e3, 1e6, 1e-6, 1e-9, 1e-12}; - int i; - int f=0; - char *e; - double ret; - char *s = m_p; - - for (i=1; i<6;i++) - if (strncmp(s, macs[i], strlen(macs[i])) == 0) - f = i; - ret = strtod(s+strlen(macs[f]), &e); - if ((f>0) && (*e != ')')) - fatalerror("Parser: Error with parameter ...\n"); - if (f>0) - e++; - m_p = e; - return ret * facs[f]; - } - - char * m_p; - netlist_setup_t &m_setup; - -}; - - -// ---------------------------------------------------------------------------------------- -// netdev_mainclock -// ---------------------------------------------------------------------------------------- - -ATTR_HOT inline void netdev_mainclock::mc_update(net_output_t &Q, const netlist_time curtime) -{ - Q.m_new_Q = !Q.m_new_Q; - Q.set_time(curtime); - Q.update_devs(); -} - -ATTR_COLD NETLIB_START(netdev_mainclock) -{ - register_output("Q", m_Q); - - register_param("FREQ", m_freq, 7159000.0 * 5); - m_inc = netlist_time::from_hz(m_freq.Value()*2); - -} - -ATTR_HOT NETLIB_UPDATE_PARAM(netdev_mainclock) -{ - m_inc = netlist_time::from_hz(m_freq.Value()*2); -} - -ATTR_HOT NETLIB_UPDATE(netdev_mainclock) -{ - // this is only called during setup ... - m_Q.m_new_Q = !m_Q.m_new_Q; - m_Q.set_time(m_netlist->time() + m_inc); -} - - -// ---------------------------------------------------------------------------------------- -// netdev_a_to_d -// ---------------------------------------------------------------------------------------- - -class netdev_a_to_d_proxy : public net_device_t -{ -public: - netdev_a_to_d_proxy(net_input_t &in_proxied) - : net_device_t() - { - assert(in_proxied.object_type(SIGNAL_MASK) == SIGNAL_DIGITAL); - m_I.m_high_thresh_V = in_proxied.m_high_thresh_V; - m_I.m_low_thresh_V = in_proxied.m_low_thresh_V; - } - - virtual ~netdev_a_to_d_proxy() {} - - analog_input_t m_I; - ttl_output_t m_Q; - -protected: - void start() - { - m_I.init_input(this); - - m_Q.init_terminal(this); - m_Q.initial(1); - } - - ATTR_HOT ATTR_ALIGN void update() - { - if (m_I.Q_Analog() > m_I.m_high_thresh_V) - OUTLOGIC(m_Q, 1, NLTIME_FROM_NS(1)); - else if (m_I.Q_Analog() < m_I.m_low_thresh_V) - OUTLOGIC(m_Q, 0, NLTIME_FROM_NS(1)); - } - -}; - -// ---------------------------------------------------------------------------------------- -// netdev_d_to_a -// ---------------------------------------------------------------------------------------- - -class netdev_d_to_a_proxy : public net_device_t -{ -public: - netdev_d_to_a_proxy(net_output_t &out_proxied) - : net_device_t() - { - assert(out_proxied.object_type(SIGNAL_MASK) == SIGNAL_DIGITAL); - m_low_V = out_proxied.m_low_V; - m_high_V = out_proxied.m_high_V; - } - - virtual ~netdev_d_to_a_proxy() {} - - ttl_input_t m_I; - analog_output_t m_Q; - -protected: - void start() - { - m_I.init_input(this); - m_Q.init_terminal(this); - m_Q.initial(0); - } - - ATTR_HOT ATTR_ALIGN void update() - { - OUTANALOG(m_Q, INPLOGIC(m_I) ? m_high_V : m_low_V, NLTIME_FROM_NS(1)); - } - -private: - double m_low_V; - double m_high_V; -}; - -// ---------------------------------------------------------------------------------------- -// netdev_const -// ---------------------------------------------------------------------------------------- - -NETLIB_START(netdev_ttl_const) -{ - register_output("Q", m_Q); - register_param("CONST", m_const, 0.0); -} - -NETLIB_UPDATE(netdev_ttl_const) -{ -} - -NETLIB_UPDATE_PARAM(netdev_ttl_const) -{ - OUTLOGIC(m_Q, m_const.ValueInt(), NLTIME_IMMEDIATE); -} - -NETLIB_START(netdev_analog_const) -{ - register_output("Q", m_Q); - register_param("CONST", m_const, 0.0); -} - -NETLIB_UPDATE(netdev_analog_const) -{ -} - -NETLIB_UPDATE_PARAM(netdev_analog_const) -{ - m_Q.initial(m_const.Value()); -} - -// ---------------------------------------------------------------------------------------- -// netlist_base_t -// ---------------------------------------------------------------------------------------- - - -NETLIB_UPDATE(netdev_analog_callback) -{ - // FIXME: Remove after device cleanup - if (!m_callback.isnull()) - m_callback(INPANALOG(m_in)); -} - -netlist_base_t::netlist_base_t() - : m_mainclock(NULL), - m_time_ps(netlist_time::zero), - m_rem(0), - m_div(NETLIST_DIV) -{ -} - -netlist_base_t::~netlist_base_t() -{ -} - -ATTR_COLD void netlist_base_t::set_mainclock_dev(netdev_mainclock *dev) -{ - m_mainclock = dev; -} - -ATTR_COLD void netlist_base_t::reset() -{ - m_time_ps = netlist_time::zero; - m_rem = 0; - m_queue.clear(); - if (m_mainclock != NULL) - m_mainclock->m_Q.set_time(netlist_time::zero); -} - - -void netlist_base_t::set_clock_freq(UINT64 clockfreq) -{ - m_div = netlist_time::from_hz(clockfreq).as_raw(); - m_rem = 0; - assert_always(m_div == NETLIST_DIV, "netlist: illegal clock!"); - VERBOSE_OUT(("Setting clock %" I64FMT "d and divisor %d\n", clockfreq, m_div)); -} - -ATTR_HOT ATTR_ALIGN inline void netlist_base_t::update_time(const netlist_time t, INT32 &atime) -{ - if (NETLIST_DIV_BITS == 0) - { - const netlist_time delta = t - m_time_ps; - m_time_ps = t; - atime -= delta.as_raw(); - } else { - const netlist_time delta = t - m_time_ps + netlist_time::from_raw(m_rem); - m_time_ps = t; - m_rem = delta.as_raw() & NETLIST_MASK; - atime -= (delta.as_raw() >> NETLIST_DIV_BITS); - - // The folling is suitable for non-power of 2 m_divs ... - // atime -= divu_64x32_rem(delta.as_raw(), m_div, &m_rem); - } -} - -ATTR_HOT ATTR_ALIGN void netlist_base_t::process_list(INT32 &atime) -{ - if (m_mainclock == NULL) - { - while ( (atime > 0) && (m_queue.is_not_empty())) - { - const queue_t::entry_t e = m_queue.pop(); - update_time(e.time(), atime); - - if (FATAL_ERROR_AFTER_NS) - printf("%s\n", e.object().netdev()->name().cstr()); - - e.object().update_devs(); - - add_to_stat(m_perf_out_processed, 1); - - if (FATAL_ERROR_AFTER_NS) - if (time() > NLTIME_FROM_NS(FATAL_ERROR_AFTER_NS)) - fatalerror("Stopped"); - } - - if (atime > 0) - { - m_time_ps += netlist_time::from_raw(atime * m_div); - atime = 0; - } - } else { - net_output_t &mcQ = m_mainclock->m_Q; - const netlist_time inc = m_mainclock->m_inc; - - while (atime > 0) - { - if (m_queue.is_not_empty()) - { - while (m_queue.peek().time() > mcQ.time()) - { - update_time(mcQ.time(), atime); - - netdev_mainclock::mc_update(mcQ, time() + inc); - - } - const queue_t::entry_t e = m_queue.pop(); - - update_time(e.time(), atime); - - e.object().update_devs(); - - } else { - update_time(mcQ.time(), atime); - - netdev_mainclock::mc_update(mcQ, time() + inc); - } - if (FATAL_ERROR_AFTER_NS) - if (time() > NLTIME_FROM_NS(FATAL_ERROR_AFTER_NS)) - fatalerror("Stopped"); - - add_to_stat(m_perf_out_processed, 1); - } - - if (atime > 0) - { - m_time_ps += netlist_time::from_raw(atime * m_div); - atime = 0; - } - } -} - -// ---------------------------------------------------------------------------------------- -// Default netlist elements ... -// ---------------------------------------------------------------------------------------- - - -static NETLIST_START(base) - NETDEV_TTL_CONST(ttlhigh, 1) - NETDEV_TTL_CONST(ttllow, 0) - NETDEV_ANALOG_CONST(NC, NETLIST_HIGHIMP_V) -NETLIST_END - -// ---------------------------------------------------------------------------------------- -// netlist_setup_t -// ---------------------------------------------------------------------------------------- - -netlist_setup_t::netlist_setup_t(netlist_base_t &netlist) - : m_netlist(netlist) -{ - NETLIST_NAME(base)(*this); -} - -template <class T> -static void tagmap_free_entries(T &tm) -{ - for (typename T::entry_t *entry = tm.first(); entry != NULL; entry = tm.next(entry)) - { - delete entry->object(); - } - tm.reset(); -} - -netlist_setup_t::~netlist_setup_t() -{ - tagmap_free_entries<tagmap_devices_t>(m_devices); - tagmap_free_entries<tagmap_astring_t>(m_links); - tagmap_free_entries<tagmap_astring_t>(m_alias); - m_params.reset(); - m_terminals.reset(); -} - -net_device_t *netlist_setup_t::register_dev(net_device_t *dev) -{ - if (!(m_devices.add(dev->name(), dev, false)==TMERR_NONE)) - fatalerror("Error adding %s to device list\n", dev->name().cstr()); - return dev; -} - -template <class T> -static void remove_start_with(T &hm, astring &sw) -{ - typename T::entry_t *entry = hm.first(); - while (entry != NULL) - { - typename T::entry_t *next = hm.next(entry); - if (sw.cmpsubstr(entry->tag(), 0, sw.len()) == 0) - { - VERBOSE_OUT(("removing %s\n", entry->tag().cstr())); - hm.remove(entry->object()); - } - entry = next; - } -} - -void netlist_setup_t::remove_dev(const astring &name) -{ - net_device_t *dev = m_devices.find(name); - astring temp = name; - if (dev == NULL) - fatalerror("Device %s does not exist\n", name.cstr()); - - temp.cat("."); - - //remove_start_with<tagmap_input_t>(m_inputs, temp); - remove_start_with<tagmap_terminal_t>(m_terminals, temp); - remove_start_with<tagmap_param_t>(m_params, temp); - remove_start_with<tagmap_astring_t>(m_links, temp); - m_devices.remove(name); -} - -void netlist_setup_t::register_callback(const astring &devname, net_output_delegate delegate) -{ - netdev_analog_callback *dev = (netdev_analog_callback *) m_devices.find(devname); - if (dev == NULL) - fatalerror("did not find device %s\n", devname.cstr()); - dev->register_callback(delegate); -} - -void netlist_setup_t::register_alias(const astring &alias, const astring &out) -{ - if (!(m_alias.add(alias, new astring(out), false)==TMERR_NONE)) - fatalerror("Error adding alias %s to alias list\n", alias.cstr()); -} - -void netlist_setup_t::register_output(net_core_device_t &dev, net_core_device_t &upd_dev, const astring &name, net_output_t &out) -{ - VERBOSE_OUT(("out %s\n", name.cstr())); - astring temp = dev.name(); - temp.cat("."); - temp.cat(name); - out.init_terminal(&upd_dev); - if (!(m_terminals.add(temp, &out, false)==TMERR_NONE)) - fatalerror("Error adding output %s to output list\n", name.cstr()); -} - -void netlist_setup_t::register_input(net_device_t &dev, net_core_device_t &upd_dev, const astring &name, net_input_t &inp, net_input_t::net_input_state type) -{ - VERBOSE_OUT(("input %s\n", name.cstr())); - astring temp = dev.name(); - temp.cat("."); - temp.cat(name); - inp.init_input(&upd_dev, type); - dev.m_inputs.add(temp); - if (!(m_terminals.add(temp, &inp, false) == TMERR_NONE)) - fatalerror("Error adding input %s to input list\n", name.cstr()); -} - -void netlist_setup_t::register_link(const astring &sin, const astring &sout) -{ - const astring *temp = new astring(sout); - VERBOSE_OUT(("link %s <== %s\n", sin.cstr(), sout.cstr())); - if (!(m_links.add(sin, temp, false)==TMERR_NONE)) - fatalerror("Error adding link %s<==%s to link list\n", sin.cstr(), sout.cstr()); -} - - -void netlist_setup_t::register_param(const astring &name, net_param_t *param) -{ - astring temp = param->netdev().name(); - temp.cat("."); - temp.cat(name); - if (!(m_params.add(temp, param, false)==TMERR_NONE)) - fatalerror("Error adding parameter %s to parameter list\n", name.cstr()); -} - - -const astring &netlist_setup_t::resolve_alias(const astring &name) const -{ - const astring *ret = m_alias.find(name); - if (ret != NULL) - return *ret; - return name; -} - -net_output_t *netlist_setup_t::find_output_exact(const astring &outname_in) -{ - net_terminal_t *term = m_terminals.find(outname_in); - return dynamic_cast<net_output_t *>(term); -} - -net_output_t &netlist_setup_t::find_output(const astring &outname_in) -{ - const astring &outname = resolve_alias(outname_in); - net_output_t *ret; - - ret = find_output_exact(outname); - /* look for default */ - if (ret == NULL) - { - /* look for ".Q" std output */ - astring s = outname; - s.cat(".Q"); - ret = find_output_exact(s); - } - if (ret == NULL) - fatalerror("output %s(%s) not found!\n", outname_in.cstr(), outname.cstr()); - VERBOSE_OUT(("Found input %s\n", outname.cstr())); - return *ret; -} - -net_param_t &netlist_setup_t::find_param(const astring ¶m_in) -{ - const astring &outname = resolve_alias(param_in); - net_param_t *ret; - - ret = m_params.find(outname); - if (ret == NULL) - fatalerror("parameter %s(%s) not found!\n", param_in.cstr(), outname.cstr()); - VERBOSE_OUT(("Found parameter %s\n", outname.cstr())); - return *ret; -} - -void netlist_setup_t::resolve_inputs(void) -{ - VERBOSE_OUT(("Resolving ...\n")); - int proxy_cnt = 0; - for (tagmap_astring_t::entry_t *entry = m_links.first(); entry != NULL; entry = m_links.next(entry)) - { - const astring *sout = entry->object(); - astring sin = entry->tag(); - net_input_t *in = dynamic_cast<net_input_t *>(m_terminals.find(sin)); - - if (in == NULL) - fatalerror("Unable to find %s\n", sin.cstr()); - - net_output_t &out = find_output(sout->cstr()); - if (out.object_type(net_output_t::SIGNAL_MASK) == net_output_t::SIGNAL_ANALOG - && in->object_type(net_output_t::SIGNAL_MASK) == net_output_t::SIGNAL_DIGITAL) - { - netdev_a_to_d_proxy *proxy = new netdev_a_to_d_proxy(*in); - astring x = ""; - x.printf("proxy_ad_%d", proxy_cnt++); - - proxy->init(*this, x.cstr()); - register_dev(proxy); - - in->set_output(proxy->m_Q); - proxy->m_Q.register_con(*in); - proxy->m_I.set_output(out); - out.register_con(proxy->m_I); - - } - else if (out.object_type(net_output_t::SIGNAL_MASK) == net_output_t::SIGNAL_DIGITAL - && in->object_type(net_output_t::SIGNAL_MASK) == net_output_t::SIGNAL_ANALOG) - { - //printf("here 1\n"); - netdev_d_to_a_proxy *proxy = new netdev_d_to_a_proxy(out); - astring x = ""; - x.printf("proxy_da_%d", proxy_cnt++); - proxy->init(*this, x.cstr()); - register_dev(proxy); - - in->set_output(proxy->m_Q); - proxy->m_Q.register_con(*in); - proxy->m_I.set_output(out); - out.register_con(proxy->m_I); - //printf("here 2\n"); - } - else - { - in->set_output(out); - out.register_con(*in); - } - } - - /* find the main clock ... */ - for (tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry)) - { - net_device_t *dev = entry->object(); - if (dynamic_cast<netdev_mainclock*>(dev) != NULL) - { - m_netlist.set_mainclock_dev(dynamic_cast<netdev_mainclock*>(dev)); - } - } - -#if 1 - -#else - /* make sure all outputs are triggered once */ - for (tagmap_output_t::entry_t *entry = m_outputs.first(); entry != NULL; entry = m_outputs.next(entry)) - { - net_output_t *out = entry->object(); - //if (dynamic_cast<const netdev_clock *>(out->netdev()) == NULL ) - { - out->update_devs_force(); - INT32 time = 10000; - m_netlist.process_list(time); - } - } - //m_netlist.m_queue.clear(); -#endif - - /* print all outputs */ - for (tagmap_terminal_t::entry_t *entry = m_terminals.first(); entry != NULL; entry = m_terminals.next(entry)) - { - ATTR_UNUSED net_output_t *out = dynamic_cast<net_output_t *>(entry->object()); - //if (out != NULL) - //VERBOSE_OUT(("%s %d\n", out->netdev()->name(), *out->Q_ptr())); - } - - -} - -void netlist_setup_t::step_devices_once(void) -{ - /* make sure params are set now .. */ - for (tagmap_param_t::entry_t *entry = m_params.first(); entry != NULL; entry = m_params.next(entry)) - { - entry->object()->netdev().update_param(); - } - - for (tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry)) - { - net_device_t *dev = entry->object(); - dev->update_dev(); - } -} - - -void netlist_setup_t::parse(char *buf) -{ - netlist_parser parser(*this); - parser.parse(buf); -} - -void netlist_setup_t::print_stats() -{ - if (KEEP_STATISTICS) - { - for (netlist_setup_t::tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry)) - { - //entry->object()->s - printf("Device %20s : %12d %15ld\n", entry->object()->name().cstr(), entry->object()->stat_count, (long int) entry->object()->total_time / (entry->object()->stat_count + 1)); - } - printf("Queue Start %15d\n", m_netlist.m_queue.m_prof_start); - printf("Queue End %15d\n", m_netlist.m_queue.m_prof_end); - printf("Queue Sort %15d\n", m_netlist.m_queue.m_prof_sort); - printf("Queue Move %15d\n", m_netlist.m_queue.m_prof_sortmove); - } -} - - -// ---------------------------------------------------------------------------------------- -// net_core_device_t -// ---------------------------------------------------------------------------------------- - -net_core_device_t::net_core_device_t() -: net_object_t(DEVICE) -{ -} - -ATTR_COLD void net_core_device_t::init(netlist_setup_t &setup, const astring &name) -{ - m_netlist = &setup.netlist(); - m_name = name; - -#if USE_DELEGATES -#if USE_PMFDELEGATES - void (net_core_device_t::* pFunc)() = &net_core_device_t::update; - static_update = reinterpret_cast<net_update_delegate>((this->*pFunc)); -#else - static_update = net_update_delegate(&net_core_device_t::update, "update", this); - // get the pointer to the member function -#endif -#endif - -} - -ATTR_COLD void net_device_t::init(netlist_setup_t &setup, const astring &name) -{ - net_core_device_t::init(setup, name); - m_setup = &setup; - start(); -} - - -net_core_device_t::~net_core_device_t() -{ -} - -// ---------------------------------------------------------------------------------------- -// net_device_t -// ---------------------------------------------------------------------------------------- - -ATTR_HOT ATTR_ALIGN const net_sig_t net_core_device_t::INPLOGIC_PASSIVE(logic_input_t &inp) -{ - if (inp.state() == net_input_t::INP_STATE_PASSIVE) - { - inp.activate(); - const net_sig_t ret = inp.Q(); - inp.inactivate(); - return ret; - } - else - return inp.Q(); - -} - -net_device_t::net_device_t() - : net_core_device_t(), - m_setup(NULL), - m_variable_input_count(false) -{ -} - -net_device_t::~net_device_t() -{ - //printf("~net_device_t\n"); -} - -ATTR_COLD void net_device_t::register_sub(net_core_device_t &dev, const astring &name) -{ - dev.init(*m_setup, name); -} - -void net_device_t::register_output(net_core_device_t &dev, const astring &name, net_output_t &port) -{ - m_setup->register_output(*this, dev, name, port); -} - -void net_device_t::register_output(const astring &name, net_output_t &port) -{ - m_setup->register_output(*this,*this,name, port); -} - -void net_device_t::register_input(net_core_device_t &dev, const astring &name, net_input_t &inp, net_input_t::net_input_state type) -{ - m_setup->register_input(*this, dev, name, inp, type); -} - -void net_device_t::register_input(const astring &name, net_input_t &inp, net_input_t::net_input_state type) -{ - register_input(*this, name, inp, type); -} - -void net_device_t::register_link_internal(net_core_device_t &dev, net_input_t &in, net_output_t &out, net_input_t::net_input_state aState) -{ - in.set_output(out); - in.init_input(&dev, aState); - //if (in.state() != net_input_t::INP_STATE_PASSIVE) - out.register_con(in); -} - -void net_device_t::register_link_internal(net_input_t &in, net_output_t &out, net_input_t::net_input_state aState) -{ - register_link_internal(*this, in, out, aState); -} - -void net_device_t::register_param(net_core_device_t &dev, const astring &name, net_param_t ¶m, double initialVal) -{ - param.set_netdev(dev); - param.initial(initialVal); - m_setup->register_param(name, ¶m); -} - -void net_device_t::register_param(const astring &name, net_param_t ¶m, double initialVal) -{ - register_param(*this,name, param, initialVal); -} - -// ---------------------------------------------------------------------------------------- -// net_terminal_t -// ---------------------------------------------------------------------------------------- - -ATTR_COLD void net_terminal_t::init_terminal(net_core_device_t *dev) -{ - m_netdev = dev; - m_netlist = dev->netlist(); -} - -// ---------------------------------------------------------------------------------------- -// net_input_t -// ---------------------------------------------------------------------------------------- - -ATTR_COLD void net_input_t::init_input(net_core_device_t *dev, net_input_state astate) -{ - init_terminal(dev); - m_state = astate; -} - -// ---------------------------------------------------------------------------------------- -// net_output_t -// ---------------------------------------------------------------------------------------- - -net_output_t::net_output_t(int atype) - : net_terminal_t(atype) - , m_low_V(0.0) - , m_high_V(0.0) - , m_last_Q(0) - , m_Q(0) - , m_new_Q(0) - , m_Q_analog(0.0) - , m_new_Q_analog(0.0) - , m_num_cons(0) - , m_time(netlist_time::zero) - , m_active(0) - , m_in_queue(2) -{ - //m_cons = global_alloc_array(net_input_t *, OUTPUT_MAX_CONNECTIONS); -} - -ATTR_HOT inline void net_output_t::update_dev(const net_input_t *inp, const UINT32 mask) -{ - if ((inp->state() & mask) != 0) - { - ATTR_UNUSED net_core_device_t *netdev = inp->netdev(); - begin_timing(netdev->total_time); - inc_stat(netdev->stat_count); - netdev->update_dev(); - end_timing(netdev()->total_time); - } -} - -ATTR_HOT inline void net_output_t::update_devs() -{ - - assert(m_num_cons != 0); - - const UINT32 masks[4] = { 1, 5, 3, 1 }; - m_Q = m_new_Q; - m_Q_analog = m_new_Q_analog; - m_in_queue = 2; /* mark as taken ... */ - - const UINT32 mask = masks[ (m_last_Q << 1) | m_Q ]; - - switch (m_num_cons) - { - case 2: - update_dev(m_cons[1], mask); - case 1: - update_dev(m_cons[0], mask); - break; - default: - { - for (int i=0; i < m_num_cons; i++) - update_dev(m_cons[i], mask); - } - break; - } - - m_last_Q = m_Q; -} - -ATTR_COLD void net_output_t::register_con(net_input_t &input) -{ - int i; - if (m_num_cons >= OUTPUT_MAX_CONNECTIONS) - fatalerror("Connections exceeded for %s\n", netdev()->name().cstr()); - - /* keep similar devices together */ - for (i = 0; i < m_num_cons; i++) - if (m_cons[i]->netdev() == input.netdev()) - break; - - for (int j = m_num_cons; j > i; j--) - m_cons[j] = m_cons[j - 1]; - - m_cons[i] = &input; - m_num_cons++; - if (input.state() != net_input_t::INP_STATE_PASSIVE) - m_active++; -} - -// ---------------------------------------------------------------------------------------- // netlist_mame_device // ---------------------------------------------------------------------------------------- @@ -1104,7 +59,12 @@ const device_type NETLIST = &device_creator<netlist_mame_device>; netlist_mame_device::netlist_mame_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, NETLIST, "netlist", tag, owner, clock, "netlist_mame", __FILE__), - device_execute_interface(mconfig, *this) + device_execute_interface(mconfig, *this), + m_device_start_list(100), + m_netlist(NULL), + m_setup(NULL), + m_setup_func(NULL), + m_icount(0) { } @@ -1198,6 +158,6 @@ ATTR_HOT void netlist_mame_device::execute_run() //if (check_debugger) // debugger_instruction_hook(this, 0); //m_pc); - m_netlist->process_list(m_icount); + m_netlist->process_queue(m_icount); } diff --git a/src/emu/machine/netlist.h b/src/emu/machine/netlist.h index 70b788c8f5f..dde09639b5f 100644 --- a/src/emu/machine/netlist.h +++ b/src/emu/machine/netlist.h @@ -51,140 +51,9 @@ #include "emu.h" #include "tagmap.h" +#include "netlist/nl_base.h" +#include "netlist/nl_setup.h" -//============================================================ -// SETUP -//============================================================ - -#define USE_DELEGATES (0) -/* - * The next options needs -Wno-pmf-conversions to compile and gcc - * This is intended for non-mame usage. - * - */ -#define USE_PMFDELEGATES (0) - -// Next if enabled adds 20% performance ... but is not guaranteed to be absolutely timing correct. -#define USE_DEACTIVE_DEVICE (0) - -#define OUTPUT_MAX_CONNECTIONS (48) - -// Use nano-second resolution - Sufficient for now -#define NETLIST_INTERNAL_RES (U64(1000000000)) -#define NETLIST_DIV_BITS (0) -//#define NETLIST_INTERNAL_RES (U64(1000000000000)) -//#define NETLIST_DIV_BITS (10) -#define NETLIST_DIV (U64(1) << NETLIST_DIV_BITS) -#define NETLIST_MASK (NETLIST_DIV-1) -#define NETLIST_CLOCK (NETLIST_INTERNAL_RES / NETLIST_DIV) - -#define NLTIME_FROM_NS(_t) netlist_time::from_nsec(_t) -#define NLTIME_FROM_US(_t) netlist_time::from_usec(_t) -#define NLTIME_FROM_MS(_t) netlist_time::from_msec(_t) -#define NLTIME_IMMEDIATE netlist_time::from_nsec(0) - -#define NETLIST_HIGHIMP_V (1.23456e20) /* some voltage we should never see */ - - -//============================================================ -// MACROS / inline netlist definitions -//============================================================ - -#define NET_ALIAS(_alias, _name) \ - netlist.register_alias(# _alias, # _name); -#define NET_NEW(_type , _name) net_create_device_by_classname(# _type, netlist, # _name) - -#define NET_REGISTER_DEV(_type, _name) \ - netlist.register_dev(NET_NEW(_type, _name)); -#define NET_REMOVE_DEV(_name) \ - netlist.remove_dev(# _name); -#define NET_REGISTER_SIGNAL(_type, _name) \ - NET_REGISTER_DEV(_type ## _ ## sig, _name) -#define NET_CONNECT(_name, _input, _output) \ - netlist.register_link(# _name "." # _input, # _output); -#define NETDEV_PARAM(_name, _val) \ - netlist.find_param(# _name).initial(_val); - -#define NETLIST_NAME(_name) netlist ## _ ## _name - -#define NETLIST_START(_name) \ -ATTR_COLD void NETLIST_NAME(_name)(netlist_setup_t &netlist) \ -{ - -#define NETLIST_END } - -#define NETLIST_INCLUDE(_name) \ - NETLIST_NAME(_name)(netlist); - -#define NETLIST_MEMREGION(_name) \ - netlist.parse((char *)downcast<netlist_t &>(netlist.netlist()).machine().root_device().memregion(_name)->base()); - -#if defined(__GNUC__) && (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) -#if !defined(__ppc__) && !defined (__PPC__) && !defined(__ppc64__) && !defined(__PPC64__) -#define ATTR_ALIGN __attribute__ ((aligned(128))) -#else -#define ATTR_ALIGN -#endif -#else -#define ATTR_ALIGN -#endif - -//============================================================ -// MACROS / netlist devices -//============================================================ - -#define NETLIB_UPDATE(_chip) ATTR_HOT ATTR_ALIGN void _chip :: update(void) -#define NETLIB_START(_chip) ATTR_COLD void _chip :: start(void) -//#define NETLIB_CONSTRUCTOR(_chip) ATTR_COLD _chip :: _chip (netlist_setup_t &setup, const char *name) -// : net_device_t(setup, name) - -#define NETLIB_UPDATE_PARAM(_chip) ATTR_HOT ATTR_ALIGN void _chip :: update_param(void) -#define NETLIB_FUNC_VOID(_chip, _name, _params) ATTR_HOT ATTR_ALIGN inline void _chip :: _name _params - -#define NETLIB_SIGNAL(_name, _num_input, _check, _invert) \ - class _name : public net_signal_t<_num_input, _check, _invert> \ - { \ - public: \ - _name () \ - : net_signal_t<_num_input, _check, _invert>() { } \ - }; - -#define NETLIB_DEVICE(_name, _priv) \ - class _name : public net_device_t \ - { \ - public: \ - _name () \ - : net_device_t() { } \ - protected: \ - ATTR_HOT void update(); \ - ATTR_HOT void start(); \ - _priv \ - } - -#define NETLIB_SUBDEVICE(_name, _priv) \ - class _name : public net_core_device_t \ - { \ - public: \ - _name () \ - : net_core_device_t() \ - { } \ - /*protected:*/ \ - ATTR_HOT void update(); \ - _priv \ - } - -#define NETLIB_DEVICE_WITH_PARAMS(_name, _priv) \ - class _name : public net_device_t \ - { \ - public: \ - _name () \ - : net_device_t() { } \ - ATTR_HOT void update_param(); \ - ATTR_HOT void update(); \ - ATTR_HOT void start(); \ - /* protected: */ \ - _priv \ - } // MAME specific #define MCFG_NETLIST_ADD(_tag, _setup ) \ @@ -196,1240 +65,9 @@ ATTR_COLD void NETLIST_NAME(_name)(netlist_setup_t &netlist) \ #define MCFG_NETLIST_SETUP(_setup) \ netlist_mame_device::static_set_constructor(*device, NETLIST_NAME(_setup)); -// ---------------------------------------------------------------------------------------- -// Type definitions -// ---------------------------------------------------------------------------------------- - -class net_core_device_t; - -#if USE_DELEGATES -#if USE_PMFDELEGATES -typedef void (*net_update_delegate)(net_core_device_t *); -#else -typedef delegate<void ()> net_update_delegate; -#endif -#endif - -typedef UINT8 net_sig_t; - - -typedef delegate<void (const double)> net_output_delegate; - -// ---------------------------------------------------------------------------------------- -// Support classes -// ---------------------------------------------------------------------------------------- - -struct netlist_time -{ -public: - - typedef UINT64 INTERNALTYPE; - - static const INTERNALTYPE RESOLUTION = NETLIST_INTERNAL_RES; - - inline netlist_time() : m_time(0) {} - - friend inline const netlist_time operator-(const netlist_time &left, const netlist_time &right); - friend inline const netlist_time operator+(const netlist_time &left, const netlist_time &right); - friend inline const netlist_time operator*(const netlist_time &left, const UINT32 factor); - friend inline bool operator>(const netlist_time &left, const netlist_time &right); - friend inline bool operator<(const netlist_time &left, const netlist_time &right); - friend inline bool operator>=(const netlist_time &left, const netlist_time &right); - friend inline bool operator<=(const netlist_time &left, const netlist_time &right); - - ATTR_HOT inline const netlist_time &operator=(const netlist_time &right) { m_time = right.m_time; return *this; } - ATTR_HOT inline const netlist_time &operator+=(const netlist_time &right) { m_time += right.m_time; return *this; } - - ATTR_HOT inline const INTERNALTYPE as_raw() const { return m_time; } - - ATTR_HOT static inline const netlist_time from_nsec(const int ns) { return netlist_time((UINT64) ns * (RESOLUTION / U64(1000000000))); } - ATTR_HOT static inline const netlist_time from_usec(const int us) { return netlist_time((UINT64) us * (RESOLUTION / U64(1000000))); } - ATTR_HOT static inline const netlist_time from_msec(const int ms) { return netlist_time((UINT64) ms * (RESOLUTION / U64(1000))); } - ATTR_HOT static inline const netlist_time from_hz(const UINT64 hz) { return netlist_time(RESOLUTION / hz); } - ATTR_HOT static inline const netlist_time from_raw(const INTERNALTYPE raw) { return netlist_time(raw); } - - static const netlist_time zero; - -protected: - - ATTR_HOT inline netlist_time(const INTERNALTYPE val) : m_time(val) {} - - INTERNALTYPE m_time; -}; - -ATTR_HOT inline const netlist_time operator-(const netlist_time &left, const netlist_time &right) -{ - return netlist_time::from_raw(left.m_time - right.m_time); -} - -ATTR_HOT inline const netlist_time operator*(const netlist_time &left, const UINT32 factor) -{ - return netlist_time::from_raw(left.m_time * factor); -} - -ATTR_HOT inline const netlist_time operator+(const netlist_time &left, const netlist_time &right) -{ - return netlist_time::from_raw(left.m_time + right.m_time); -} - -ATTR_HOT inline bool operator<(const netlist_time &left, const netlist_time &right) -{ - return (left.m_time < right.m_time); -} - -ATTR_HOT inline bool operator>(const netlist_time &left, const netlist_time &right) -{ - return (left.m_time > right.m_time); -} - -ATTR_HOT inline bool operator<=(const netlist_time &left, const netlist_time &right) -{ - return (left.m_time <= right.m_time); -} - -ATTR_HOT inline bool operator>=(const netlist_time &left, const netlist_time &right) -{ - return (left.m_time >= right.m_time); -} - -template <class _ListClass, int _NumElements> -struct net_list_t -{ -public: - net_list_t() - { - m_list = global_alloc_array(_ListClass, _NumElements); - m_ptr = m_list; - m_ptr--; - } - ~net_list_t() - { - global_free(m_list); - } - ATTR_HOT inline void add(const _ListClass elem) - { - assert(m_ptr-m_list <= _NumElements - 1); - - *(++m_ptr) = elem; - } - ATTR_HOT inline _ListClass *first() { return &m_list[0]; } - ATTR_HOT inline _ListClass *last() { return m_ptr; } - ATTR_HOT inline _ListClass *item(int i) { return &m_list[i]; } - inline int count() const { return m_ptr - m_list + 1; } - ATTR_HOT inline bool empty() { return (m_ptr < m_list); } - ATTR_HOT inline void clear() { m_ptr = m_list - 1; } -private: - _ListClass * m_ptr; - _ListClass * m_list; - //_ListClass m_list[_NumElements]; -}; - -// ---------------------------------------------------------------------------------------- -// forward definitions -// ---------------------------------------------------------------------------------------- - -class net_output_t; -class net_core_device_t; -class net_param_t; -class netlist_setup_t; -class netlist_base_t; - -// ---------------------------------------------------------------------------------------- -// timed queue -// ---------------------------------------------------------------------------------------- - -//#define SIZE ((1 << _Size) - 1) - -class netlist_timed_queue -{ -public: - - static const int SIZE = ((1 << 11) - 1); - - typedef net_output_t element_t; - - struct entry_t - { - public: - inline entry_t() - : m_time(netlist_time::zero), m_object(NULL) {} - inline entry_t(const netlist_time atime, element_t &elem) : m_time(atime), m_object(&elem) {} - ATTR_HOT inline const netlist_time &time() const { return m_time; } - ATTR_HOT inline element_t & object() const { return *m_object; } - private: - netlist_time m_time; - element_t *m_object; - }; - - netlist_timed_queue() - { - //m_list = global_alloc_array(entry_t, SIZE); - clear(); - } - - ATTR_HOT inline bool is_empty() const { return (m_end == &m_list[0]); } - ATTR_HOT inline bool is_not_empty() const { return (m_end > &m_list[0]); } - - ATTR_HOT ATTR_ALIGN inline void push(const entry_t &e) - { - if (is_empty() || (e.time() <= (m_end - 1)->time())) - { - *m_end++ = e; - //inc_stat(m_prof_end); - } - else - { - entry_t * RESTRICT i = m_end++; - while ((i>&m_list[0]) && (e.time() > (i-1)->time()) ) - { - i--; - *(i+1) = *i; - //inc_stat(m_prof_sortmove); - } - *i = e; - //inc_stat(m_prof_sort); - } - assert(m_end - m_list < SIZE); - } - - ATTR_HOT inline const entry_t pop() - { - return *--m_end; - } - - ATTR_HOT inline const entry_t peek() const - { - return *(m_end-1); - } - - ATTR_COLD void clear() - { - m_end = &m_list[0]; - } - // profiling - - INT32 m_prof_start; - INT32 m_prof_end; - INT32 m_prof_sortmove; - INT32 m_prof_sort; -private: - - entry_t * RESTRICT m_end; - //entry_t *m_list; - entry_t m_list[SIZE + 1]; - -}; - -// ---------------------------------------------------------------------------------------- -// net_object_t -// ---------------------------------------------------------------------------------------- - -class net_object_t -{ -public: - enum type_t { - INPUT = 0, - OUTPUT = 1, - DEVICE = 2, - PARAM = 3, - TERMINAL = 4, - NET_ANALOG = 5, - NET_DIGITAL = 6, - TYPE_MASK = 0x0f, - SIGNAL_DIGITAL = 0x00, - SIGNAL_ANALOG = 0x10, - SIGNAL_MASK = 0x10, - }; - - net_object_t(int atype) - : m_objtype(atype) {} - - virtual ~net_object_t() {} - - ATTR_HOT inline int object_type() const { return m_objtype; } - ATTR_HOT inline int object_type(const UINT32 mask) const { return m_objtype & mask; } - -private: - int m_objtype; -}; - -// ---------------------------------------------------------------------------------------- -// net_terminal_t -// ---------------------------------------------------------------------------------------- - -class net_terminal_t : public net_object_t -{ -public: - - net_terminal_t(const int atype) - : net_object_t(atype) - , m_netdev(NULL) - , m_netlist(NULL) - {} - - ATTR_COLD void init_terminal(net_core_device_t *dev); - ATTR_HOT inline net_core_device_t * RESTRICT netdev() const { return m_netdev; } - ATTR_HOT inline netlist_base_t * RESTRICT netlist() const { return m_netlist; } - -private: - net_core_device_t * RESTRICT m_netdev; - netlist_base_t * RESTRICT m_netlist; -}; - - -// ---------------------------------------------------------------------------------------- -// net_input_t -// ---------------------------------------------------------------------------------------- - -class net_input_t : public net_terminal_t -{ -public: - - enum net_input_state { - INP_STATE_PASSIVE = 0, - INP_STATE_ACTIVE = 1, - INP_STATE_HL = 2, - INP_STATE_LH = 4, - }; - - ATTR_COLD net_input_t(const int atype) - : net_terminal_t(atype) - , m_low_thresh_V(0) - , m_high_thresh_V(0) - , m_state(INP_STATE_ACTIVE) - , m_output(NULL) - {} - - ATTR_COLD void init_input(net_core_device_t *dev, net_input_state astate = INP_STATE_ACTIVE); - - ATTR_HOT inline net_output_t * RESTRICT output() const { return m_output; } - ATTR_HOT inline const bool is_state(const net_input_state astate) const { return (m_state == astate); } - ATTR_HOT inline const net_input_state state() const { return m_state; } - - ATTR_COLD void set_output(net_output_t &aout) { m_output = &aout; } - ATTR_HOT inline void inactivate(); - ATTR_HOT inline void activate(); - ATTR_HOT inline void activate_hl(); - ATTR_HOT inline void activate_lh(); - - double m_low_thresh_V; - double m_high_thresh_V; - -private: - net_input_state m_state; - net_output_t * RESTRICT m_output; -}; - -class logic_input_t : public net_input_t -{ -public: - logic_input_t() - : net_input_t(INPUT | SIGNAL_DIGITAL) - { - // default to TTL - m_low_thresh_V = 0.8; - m_high_thresh_V = 2.0; - } - - ATTR_HOT inline const net_sig_t Q() const; - ATTR_HOT inline const net_sig_t last_Q() const; - - ATTR_COLD inline void set_thresholds(const double low, const double high) - { - m_low_thresh_V = low; - m_high_thresh_V = high; - } -}; - -class ttl_input_t : public logic_input_t -{ -public: - ttl_input_t() - : logic_input_t() { set_thresholds(0.8 , 2.0); } -}; - -class analog_input_t : public net_input_t -{ -public: - analog_input_t() - : net_input_t(INPUT | SIGNAL_ANALOG) { } - - ATTR_HOT inline const bool is_highz() const; - ATTR_HOT inline const double Q_Analog() const; -}; - -//#define INPVAL(_x) (_x).Q() - -// ---------------------------------------------------------------------------------------- -// net_output_t -// ---------------------------------------------------------------------------------------- - -class netdev_mainclock; - -class net_output_t : public net_terminal_t -{ -public: - - net_output_t(int atype); - - friend const net_sig_t logic_input_t::Q() const; - friend const double analog_input_t::Q_Analog() const; - friend const bool analog_input_t::is_highz() const; - friend class netdev_mainclock; - - ATTR_HOT inline const net_sig_t last_Q() const { return m_last_Q; } - ATTR_HOT inline const net_sig_t new_Q() const { return m_new_Q; } - - ATTR_COLD void register_con(net_input_t &inp); - - ATTR_HOT inline void update_devs(); - - ATTR_HOT inline void inc_active(); - ATTR_HOT inline void dec_active(); - - ATTR_HOT inline const int active_count() const { return m_active; } - ATTR_HOT inline const netlist_time time() const { return m_time; } - ATTR_HOT inline void set_time(const netlist_time ntime) { m_time = ntime; } - - double m_low_V; - double m_high_V; - -protected: - - /* prohibit use in device functions - * current (pending) state can be inquired using new_Q() - */ - ATTR_HOT inline const net_sig_t Q() const - { - assert(object_type(SIGNAL_MASK) == SIGNAL_DIGITAL); - return m_Q; - } - ATTR_HOT inline const double Q_Analog() const - { - assert(object_type(SIGNAL_MASK) == SIGNAL_ANALOG); - return m_Q_analog; - } - - ATTR_HOT inline void push_to_queue(const netlist_time &delay); - - net_sig_t m_last_Q; - net_sig_t m_Q; - net_sig_t m_new_Q; - - double m_Q_analog; - double m_new_Q_analog; - - UINT32 m_num_cons; -private: - ATTR_HOT void update_dev(const net_input_t *inp, const UINT32 mask); - - netlist_time m_time; - - INT32 m_active; - - UINT32 m_in_queue; /* 0: not in queue, 1: in queue, 2: last was taken */ - - net_input_t * RESTRICT m_cons[OUTPUT_MAX_CONNECTIONS]; -}; - - -class logic_output_t : public net_output_t -{ -public: - - logic_output_t() - : net_output_t(OUTPUT | SIGNAL_DIGITAL) - { - // Default to TTL - m_low_V = 0.1; // these depend on sinked/sourced current. Values should be suitable for typical applications. - m_high_V = 4.8; - } - - ATTR_COLD void initial(const net_sig_t val) { m_Q = val; m_new_Q = val; m_last_Q = !val; } - - ATTR_HOT inline void set_Q(const net_sig_t newQ, const netlist_time &delay) - { - if (EXPECTED(newQ != m_new_Q)) - { - m_new_Q = newQ; - if (m_num_cons) - push_to_queue(delay); - } - } - - ATTR_COLD inline void set_levels(const double low, const double high) - { - m_low_V = low; - m_high_V = high; - } -}; - -class ttl_output_t : public logic_output_t -{ -public: - - ttl_output_t() - : logic_output_t() - { set_levels(0.3, 3.4); } - -}; - -class analog_output_t : public net_output_t -{ -public: - - analog_output_t() - : net_output_t(OUTPUT | SIGNAL_ANALOG) { } - - ATTR_COLD void initial(const double val) { m_Q_analog = val; m_new_Q_analog = val; } - - ATTR_HOT inline void set_Q(const double newQ, const netlist_time &delay) - { - if (newQ != m_new_Q_analog) - { - m_new_Q_analog = newQ; - push_to_queue(delay); - } - } - -}; - -// ---------------------------------------------------------------------------------------- -// net_device_t -// ---------------------------------------------------------------------------------------- - -class net_core_device_t : public net_object_t -{ -public: - - net_core_device_t(); - - virtual ~net_core_device_t(); - - ATTR_COLD virtual void init(netlist_setup_t &setup, const astring &name); - - ATTR_COLD const astring &name() const { return m_name; } - - ATTR_HOT virtual void update_param() {} - - ATTR_HOT const net_sig_t INPLOGIC_PASSIVE(logic_input_t &inp); - - ATTR_HOT inline void update_dev() - { -#if USE_DELEGATES -#if USE_PMFDELEGATES - static_update(this); -#else - static_update(); -#endif -#else - update(); -#endif - } - - ATTR_HOT inline const net_sig_t INPLOGIC(const logic_input_t &inp) const - { - assert(inp.state() != net_input_t::INP_STATE_PASSIVE); - return inp.Q(); - } - - ATTR_HOT inline void OUTLOGIC(logic_output_t &out, const net_sig_t val, const netlist_time &delay) - { - out.set_Q(val, delay); - } - - ATTR_HOT inline bool INP_HL(const logic_input_t &inp) const - { - return ((inp.last_Q() & !inp.Q()) == 1); - } - - ATTR_HOT inline bool INP_LH(const logic_input_t &inp) const - { - return ((!inp.last_Q() & inp.Q()) == 1); - } - - ATTR_HOT inline const double INPANALOG(const analog_input_t &inp) const { return inp.Q_Analog(); } - - ATTR_HOT inline void OUTANALOG(analog_output_t &out, const double val, const netlist_time &delay) - { - out.set_Q(val, delay); - } - - ATTR_HOT inline netlist_base_t *netlist() const { return m_netlist; } - - ATTR_HOT virtual void inc_active() { } - - ATTR_HOT virtual void dec_active() { /*printf("DeActivate %s\n", m_name);*/ } - - /* stats */ - osd_ticks_t total_time; - INT32 stat_count; - -#if USE_DELEGATES - net_update_delegate static_update; -#endif - -protected: - - ATTR_HOT virtual void update() { } - ATTR_HOT virtual void start() { } - - netlist_base_t * RESTRICT m_netlist; - -private: - - astring m_name; -}; - - -class net_device_t : public net_core_device_t -{ -public: - - net_device_t(); - - virtual ~net_device_t(); - - ATTR_COLD virtual void init(netlist_setup_t &setup, const astring &name); - - ATTR_COLD const netlist_setup_t *setup() const { return m_setup; } - - ATTR_COLD bool variable_input_count() { return m_variable_input_count; } - - ATTR_COLD void register_sub(net_core_device_t &dev, const astring &name); - - ATTR_COLD void register_output(const astring &name, net_output_t &out); - ATTR_COLD void register_output(net_core_device_t &dev, const astring &name, net_output_t &out); - - ATTR_COLD void register_input(const astring &name, net_input_t &in, net_input_t::net_input_state state = net_input_t::INP_STATE_ACTIVE); - ATTR_COLD void register_input(net_core_device_t &dev, const astring &name, net_input_t &in, net_input_t::net_input_state state = net_input_t::INP_STATE_ACTIVE); - - ATTR_COLD void register_link_internal(net_input_t &in, net_output_t &out, net_input_t::net_input_state aState); - ATTR_COLD void register_link_internal(net_core_device_t &dev, net_input_t &in, net_output_t &out, net_input_t::net_input_state aState); - - net_list_t<astring, 20> m_inputs; - -protected: - - virtual void update() { } - ATTR_HOT virtual void start() { } - - ATTR_COLD void register_param(const astring &sname, net_param_t ¶m, const double initialVal = 0.0); - ATTR_COLD void register_param(net_core_device_t &dev, const astring &sname, net_param_t ¶m, const double initialVal = 0.0); - - netlist_setup_t *m_setup; - bool m_variable_input_count; - -private: -}; - -class net_param_t -{ -public: - net_param_t() - : m_param(0.0) - , m_netdev(NULL) - { } - - inline void setTo(const double param) { m_param = param; m_netdev->update_param(); } - inline void setTo(const int param) { m_param = param; m_netdev->update_param(); } - inline void initial(const double val) { m_param = val; } - inline void initial(const int val) { m_param = val; } - - ATTR_HOT inline double Value() const { return m_param; } - ATTR_HOT inline int ValueInt() const { return (int) m_param; } - - ATTR_HOT inline net_core_device_t &netdev() const { return *m_netdev; } - void set_netdev(net_core_device_t &dev) { m_netdev = &dev; } - -private: - - double m_param; - net_core_device_t *m_netdev; -}; - -// ---------------------------------------------------------------------------------------- -// net_signal_t -// ---------------------------------------------------------------------------------------- - -template <int _numdev> -class net_signal_base_t : public net_device_t -{ -public: - net_signal_base_t() - : net_device_t(), m_active(1) { } - - ATTR_COLD void start() - { - const char *sIN[8] = { "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8" }; - - register_output("Q", m_Q); - for (int i=0; i < _numdev; i++) - { - register_input(sIN[i], m_i[i], net_input_t::INP_STATE_ACTIVE); - } - m_Q.initial(1); - } - -#if (USE_DEACTIVE_DEVICE) - ATTR_HOT void inc_active() - { - if (m_active == 0) - { - update(); - } - m_active++; - } - - ATTR_HOT void dec_active() - { - m_active--; - if (m_active == 0) - { - for (int i = 0; i< _numdev; i++) - m_i[i].inactivate(); - } - } -#endif - -public: - ttl_input_t m_i[_numdev]; - ttl_output_t m_Q; - INT8 m_active; -}; - - -template <int _numdev, int _check, int _invert> -class net_signal_t : public net_device_t -{ -public: - net_signal_t() - : net_device_t(), m_active(1) { } - - ATTR_COLD void start() - { - const char *sIN[8] = { "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8" }; - - register_output("Q", m_Q); - for (int i=0; i < _numdev; i++) - { - register_input(sIN[i], m_i[i], net_input_t::INP_STATE_ACTIVE); - } - m_Q.initial(1); - } - - #if (USE_DEACTIVE_DEVICE) - ATTR_HOT void inc_active() - { - if (m_active == 0) - { - update(); - } - m_active++; - } - - ATTR_HOT void dec_active() - { - m_active--; - if (m_active == 0) - { - for (int i = 0; i< _numdev; i++) - m_i[i].inactivate(); - } - } - #endif - - virtual void update() - { - static const netlist_time times[2] = { NLTIME_FROM_NS(22), NLTIME_FROM_NS(15) }; - int pos = -1; - - for (int i = 0; i< _numdev; i++) - { - this->m_i[i].activate(); - if (INPLOGIC(this->m_i[i]) == _check) - { - OUTLOGIC(this->m_Q, _check ^ (1 ^ _invert), times[_check]);// ? 15000 : 22000); - pos = i; - break; - } - } - if (pos >= 0) - { - for (int i = 0; i < _numdev; i++) - if (i != pos) - this->m_i[i].inactivate(); - } else - OUTLOGIC(this->m_Q,_check ^ (_invert), times[1-_check]);// ? 22000 : 15000); - } - -public: - ttl_input_t m_i[_numdev]; - ttl_output_t m_Q; - INT8 m_active; -}; - -#if 1 -template <int _check, int _invert> -class xx_net_signal_t: public net_device_t -{ -public: - xx_net_signal_t() - : net_device_t(), m_active(1) { } - - ATTR_COLD void start() - { - const char *sIN[2] = { "I1", "I2" }; - - register_output("Q", m_Q); - for (int i=0; i < 2; i++) - { - register_input(sIN[i], m_i[i], net_input_t::INP_STATE_ACTIVE); - } - m_Q.initial(1); - } - - #if (USE_DEACTIVE_DEVICE) - ATTR_HOT void inc_active() - { - if (m_active == 0) - { - update(); - } - m_active++; - } - - ATTR_HOT void dec_active() - { - m_active--; - if (m_active == 0) - { - m_i[0].inactivate(); - m_i[1].inactivate(); - } - } - #endif - - - ATTR_HOT ATTR_ALIGN void update() - { - const netlist_time times[2] = { NLTIME_FROM_NS(22), NLTIME_FROM_NS(15) }; - - int res = _invert ^ 1 ^_check; - m_i[0].activate(); - m_i[1].activate(); - if (INPLOGIC(m_i[0]) ^ _check) - { - if (INPLOGIC(m_i[1]) ^ _check) - { - res = _invert ^ _check; - } - else - m_i[0].inactivate(); - } else { - if (INPLOGIC(m_i[1]) ^ _check) - m_i[1].inactivate(); - } - OUTLOGIC(m_Q, res, times[(res & 1) ^ 1]);// ? 22000 : 15000); - } - -public: - ttl_input_t m_i[2]; - ttl_output_t m_Q; - INT8 m_active; - -}; - -template <int _check, int _invert> -class net_signal_t<2, _check, _invert> : public xx_net_signal_t<_check, _invert> -{ -public: - net_signal_t() - : xx_net_signal_t<_check, _invert>() { } -}; - -// The following did not improve performance -#if 0 - -template <UINT8 _check, UINT8 _invert> -class net_signal_t<3, _check, _invert> : public net_device_t -{ -public: - net_signal_t() : net_device_t(), m_active(1) { } - - ATTR_COLD void start() - { - const char *sIN[3] = { "I1", "I2", "I3" }; - - register_output("Q", m_Q); - for (int i=0; i < 3; i++) - { - register_input(sIN[i], m_i[i], net_input_t::INP_STATE_ACTIVE); - } - m_Q.initial(1); - } - - ATTR_HOT ATTR_ALIGN void update() - { - const netlist_time times[2] = { NLTIME_FROM_NS(22), NLTIME_FROM_NS(15) }; - //const UINT8 res_tab[4] = {1, 1, 1, 0 }; - //const UINT8 ai1[4] = {0, 1, 0, 0 }; - //const UINT8 ai2[4] = {1, 0, 1, 0 }; - - UINT8 res = _invert ^ 1 ^_check; - m_i[0].activate(); - if (INPLOGIC(m_i[0]) ^ _check) - { - m_i[1].activate(); - if (INPLOGIC(m_i[1]) ^ _check) - { - m_i[2].activate(); - if (INPLOGIC(m_i[2]) ^ _check) - { - res = _invert ^ _check; - } - else - m_i[1].inactivate(); - } - else - { - if (INPLOGIC(m_i[2]) ^ _check) - m_i[2].inactivate(); - m_i[0].inactivate(); - } - } else { - if (INPLOGIC(m_i[1]) ^ _check) - m_i[1].inactivate(); - } - OUTLOGIC(m_Q, res, times[1 - res]);// ? 22000 : 15000); - } -public: - ttl_input_t m_i[3]; - ttl_output_t m_Q; - INT8 m_active; - -}; - -#endif -#endif - -// ---------------------------------------------------------------------------------------- -// netlist_setup_t -// ---------------------------------------------------------------------------------------- - -class netlist_setup_t -{ -public: - typedef tagmap_t<net_device_t *, 393> tagmap_devices_t; - typedef tagmap_t<const astring *, 393> tagmap_astring_t; - typedef tagmap_t<net_param_t *, 393> tagmap_param_t; - typedef tagmap_t<net_terminal_t *, 393> tagmap_terminal_t; - netlist_setup_t(netlist_base_t &netlist); - ~netlist_setup_t(); - - netlist_base_t &netlist() { return m_netlist; } - - net_device_t *register_dev(net_device_t *dev); - void remove_dev(const astring &name); - - void register_output(net_core_device_t &dev, net_core_device_t &upd_dev, const astring &name, net_output_t &out); - void register_input(net_device_t &dev, net_core_device_t &upd_dev, const astring &name, net_input_t &inp, net_input_t::net_input_state type); - void register_alias(const astring &alias, const astring &out); - void register_param(const astring &sname, net_param_t *param); - - void register_link(const astring &sin, const astring &sout); - - net_output_t &find_output(const astring &outname_in); - net_param_t &find_param(const astring ¶m_in); - - void register_callback(const astring &devname, net_output_delegate delegate); - - void parse(char *buf); - - void resolve_inputs(void); - void step_devices_once(void); - - /* not ideal, but needed for save_state */ - tagmap_terminal_t m_terminals; - - void print_stats(); - -protected: - -private: - - netlist_base_t &m_netlist; - - tagmap_devices_t m_devices; - tagmap_astring_t m_alias; - //tagmap_input_t m_inputs; - tagmap_param_t m_params; - tagmap_astring_t m_links; - - net_output_t *find_output_exact(const astring &outname_in); - const astring &resolve_alias(const astring &name) const; -}; - -class netdev_mainclock; - -// ---------------------------------------------------------------------------------------- -// netlist_base_t -// ---------------------------------------------------------------------------------------- - -class netlist_base_t -{ -public: - - typedef netlist_timed_queue queue_t; - - netlist_base_t(); - virtual ~netlist_base_t(); - - void set_clock_freq(UINT64 clockfreq); - - ATTR_HOT inline void push_to_queue(net_output_t &out, const netlist_time &attime) - { - m_queue.push(queue_t::entry_t(attime, out)); - } - - ATTR_HOT void process_list(INT32 &atime); - - ATTR_HOT inline const netlist_time &time() const { return m_time_ps; } - - ATTR_COLD void set_mainclock_dev(netdev_mainclock *dev); - - ATTR_COLD void reset(); - - // FIXME: should'nt be public - queue_t m_queue; - -protected: - // performance - int m_perf_out_processed; - int m_perf_inp_processed; - int m_perf_inp_active; - -private: - netdev_mainclock *m_mainclock; - netlist_time m_time_ps; - UINT32 m_rem; - UINT32 m_div; - - - ATTR_HOT void update_time(const netlist_time t, INT32 &atime); - -}; - -// ---------------------------------------------------------------------------------------- -// netdev_mainclock -// ---------------------------------------------------------------------------------------- - -NETLIB_DEVICE_WITH_PARAMS(netdev_mainclock, - ttl_output_t m_Q; - - net_param_t m_freq; - netlist_time m_inc; - - ATTR_HOT inline static void mc_update(net_output_t &Q, const netlist_time curtime); -); - -// ---------------------------------------------------------------------------------------- -// netdev_callback -// ---------------------------------------------------------------------------------------- - -class netdev_analog_callback : public net_device_t -{ -public: - netdev_analog_callback() - : net_device_t() { } - - ATTR_COLD void start() - { - register_input("IN", m_in); - } - - void register_callback(net_output_delegate callback) - { - m_callback = callback; - } - - ATTR_HOT void update(); - - -private: - analog_input_t m_in; - net_output_delegate m_callback; -}; - -// ---------------------------------------------------------------------------------------- -// netdev_*_const -// ---------------------------------------------------------------------------------------- - -#define NETDEV_TTL_CONST(_name, _v) \ - NET_REGISTER_DEV(netdev_ttl_const, _name) \ - NETDEV_PARAM(_name.CONST, _v) -#define NETDEV_ANALOG_CONST(_name, _v) \ - NET_REGISTER_DEV(netdev_analog_const, _name) \ - NETDEV_PARAM(_name.CONST, _v) - -NETLIB_DEVICE_WITH_PARAMS(netdev_ttl_const, - ttl_output_t m_Q; - net_param_t m_const; -); - -NETLIB_DEVICE_WITH_PARAMS(netdev_analog_const, - analog_output_t m_Q; - net_param_t m_const; -); - -// ---------------------------------------------------------------------------------------- -// Inline implementations -// ---------------------------------------------------------------------------------------- - -ATTR_HOT inline void net_input_t::inactivate() -{ - if (m_state != INP_STATE_PASSIVE) - { - m_state = INP_STATE_PASSIVE; - m_output->dec_active(); - } -} - -ATTR_HOT inline void net_input_t::activate() -{ - if (m_state == INP_STATE_PASSIVE) - { - m_output->inc_active(); - m_state = INP_STATE_ACTIVE; - } -} - -ATTR_HOT inline void net_input_t::activate_hl() -{ - if (m_state == INP_STATE_PASSIVE) - { - m_output->inc_active(); - m_state = INP_STATE_HL; - } -} - -ATTR_HOT inline void net_input_t::activate_lh() -{ - if (m_state == INP_STATE_PASSIVE) - { - m_output->inc_active(); - m_state = INP_STATE_LH; - } -} - - -ATTR_HOT inline void net_output_t::push_to_queue(const netlist_time &delay) -{ - // 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) - { - //m_in_queue = 1; /* pending */ - netlist()->push_to_queue(*this, m_time); - } -} - -ATTR_HOT inline void net_output_t::inc_active() -{ - m_active++; - -#if USE_DEACTIVE_DEVICE - if (m_active == 1 && m_in_queue > 0) - { - m_last_Q = m_Q; - netdev()->inc_active(); - m_Q = m_new_Q; - } -#endif - - if (EXPECTED(m_active == 1 && m_in_queue == 0)) - { - if (EXPECTED(m_time > netlist()->time())) - { - m_in_queue = 1; /* pending */ - netlist()->push_to_queue(*this, m_time); - } - else - { - m_Q = m_last_Q = m_new_Q; - m_Q_analog = m_new_Q_analog; - m_in_queue = 2; - } - } -} - -ATTR_HOT inline void net_output_t::dec_active() -{ - m_active--; -#if (USE_DEACTIVE_DEVICE) - if (m_active == 0) - netdev()->dec_active(); -#endif -} - - - - -ATTR_HOT inline const net_sig_t logic_input_t::Q() const -{ - return output()->Q(); -} - -ATTR_HOT inline const net_sig_t logic_input_t::last_Q() const -{ - return output()->last_Q(); -} - -ATTR_HOT inline const double analog_input_t::Q_Analog() const -{ - return output()->Q_Analog(); -} - -ATTR_HOT inline const bool analog_input_t::is_highz() const -{ - return (output()->Q_Analog() == NETLIST_HIGHIMP_V); -} - -// ---------------------------------------------------------------------------------------- -// net_dev class factory -// ---------------------------------------------------------------------------------------- - -class net_device_t_base_factory -{ -public: - virtual ~net_device_t_base_factory() {} - virtual net_device_t *Create() const = 0; - - const astring &name() const { return m_name; } - const astring &classname() const { return m_classname; } -protected: - astring m_name; /* device name */ - astring m_classname; /* device class name */ -}; - -template <class C> -class net_device_t_factory : public net_device_t_base_factory -{ -public: - net_device_t_factory(const astring &name, const astring &classname) { m_name = name; m_classname = classname; } - net_device_t *Create() const - { - net_device_t *r = new C(); - //r->init(setup, name); - return r; - } -}; -net_device_t *net_create_device_by_classname(const astring &classname, netlist_setup_t &setup, const astring &icname); -net_device_t *net_create_device_by_name(const astring &name, netlist_setup_t &setup, const astring &icname); // ---------------------------------------------------------------------------------------- // MAME glue classes @@ -1479,7 +117,7 @@ public: netlist_setup_t &setup() { return *m_setup; } netlist_t &netlist() { return *m_netlist; } - net_list_t<on_device_start *, 393> m_device_start_list; + netlist_list_t<on_device_start *> m_device_start_list; protected: // device-level overrides @@ -1526,7 +164,7 @@ class netlist_mame_device::output_finder : public object_finder_base<_NETClass>, public: // construction/destruction output_finder(device_t &base, const char *tag, const char *output) - : object_finder_base<_NETClass>(base, tag), m_output(output) { } + : object_finder_base<_NETClass>(base, tag), m_netlist(NULL), m_output(output) { } // finder virtual bool findit(bool isvalidation = false) diff --git a/src/emu/netlist/net_lib.c b/src/emu/netlist/devices/net_lib.c index 09015f90907..2c255469569 100644 --- a/src/emu/netlist/net_lib.c +++ b/src/emu/netlist/devices/net_lib.c @@ -1,3 +1,5 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud /*************************************************************************** netlib.c @@ -46,6 +48,7 @@ ****************************************************************************/ #include "net_lib.h" +#include "nld_system.h" NETLIB_START(netdev_logic_input) { @@ -219,12 +222,12 @@ NETLIB_START(nicNE555N_MSTABLE) m_last = false; } -INLINE double nicNE555N_cv(nicNE555N_MSTABLE &dev) +INLINE double nicNE555N_cv(NETLIB_NAME(nicNE555N_MSTABLE) &dev) { return (dev.m_CV.is_highz() ? 0.67 * dev.m_VS.Value() : dev.INPANALOG(dev.m_CV)); } -INLINE double nicNE555N_clamp(nicNE555N_MSTABLE &dev, const double v, const double a, const double b) +INLINE double nicNE555N_clamp(NETLIB_NAME(nicNE555N_MSTABLE) &dev, const double v, const double a, const double b) { double ret = v; if (ret > dev.m_VS.Value() - a) @@ -391,7 +394,7 @@ NETLIB_FUNC_VOID(nic7448_sub, update_outputs, (UINT8 v)) } } -const UINT8 nic7448_sub::tab7448[16][7] = +const UINT8 NETLIB_NAME(nic7448_sub)::tab7448[16][7] = { { 1, 1, 1, 1, 1, 1, 0 }, /* 00 - not blanked ! */ { 0, 1, 1, 0, 0, 0, 0 }, /* 01 */ @@ -458,7 +461,7 @@ NETLIB_UPDATE(nic7450) #endif } -ATTR_HOT inline void nic7474sub::newstate(const UINT8 state) +ATTR_HOT inline void NETLIB_NAME(nic7474sub)::newstate(const UINT8 state) { static const netlist_time delay[2] = { NLTIME_FROM_NS(25), NLTIME_FROM_NS(40) }; //printf("%s %d %d %d\n", "7474", state, Q.Q(), QQ.Q()); @@ -636,7 +639,7 @@ NETLIB_UPDATE(nic7493ff) NETLIB_UPDATE(nic7493) { - net_sig_t r = INPLOGIC(m_R1) & INPLOGIC(m_R2); + netlist_sig_t r = INPLOGIC(m_R1) & INPLOGIC(m_R2); if (r) { @@ -754,7 +757,7 @@ NETLIB_START(nic74107A) sub.m_QQ.initial(1); } -ATTR_HOT inline void nic74107Asub::newstate(const net_sig_t state) +ATTR_HOT inline void NETLIB_NAME(nic74107Asub)::newstate(const netlist_sig_t state) { const netlist_time delay[2] = { NLTIME_FROM_NS(40), NLTIME_FROM_NS(25) }; #if 1 @@ -772,7 +775,7 @@ ATTR_HOT inline void nic74107Asub::newstate(const net_sig_t state) NETLIB_UPDATE(nic74107Asub) { { - net_sig_t t = m_Q.new_Q(); + netlist_sig_t t = m_Q.new_Q(); newstate((!t & m_Q1) | (t & m_Q2) | m_F); if (!m_Q1) m_clk.inactivate(); @@ -892,7 +895,7 @@ NETLIB_UPDATE(nic9316) { sub.m_loadq = INPLOGIC(m_LOADQ); sub.m_ent = INPLOGIC(m_ENT); - const net_sig_t clrq = INPLOGIC(m_CLRQ); + const netlist_sig_t clrq = INPLOGIC(m_CLRQ); if ((!sub.m_loadq || (sub.m_ent & INPLOGIC(m_ENP))) & clrq) { @@ -964,7 +967,9 @@ NETLIB_FUNC_VOID(nic9316_sub, update_outputs, (void)) #endif } -#define ENTRY(_nic, _name) new net_device_t_factory< _nic >( # _name, # _nic ), +#define xstr(s) # s +#define ENTRY1(_nic, _name) new net_device_t_factory< _nic >( # _name, xstr(_nic) ), +#define ENTRY(_nic, _name) ENTRY1(NETLIB_NAME(_nic), _name) static const net_device_t_base_factory *netregistry[] = { @@ -979,7 +984,7 @@ static const net_device_t_base_factory *netregistry[] = ENTRY(nicMultiSwitch, NETDEV_SWITCH2) ENTRY(nicRSFF, NETDEV_RSFF) ENTRY(nicMixer8, NETDEV_MIXER) - ENTRY(nic7400, TTL_7400_NAND) + ENTRY(7400, TTL_7400_NAND) ENTRY(nic7402, TTL_7402_NOR) ENTRY(nic7404, TTL_7404_INVERT) ENTRY(nic7410, TTL_7410_NAND) @@ -1005,7 +1010,7 @@ static const net_device_t_base_factory *netregistry[] = net_device_t *net_create_device_by_classname(const astring &classname, netlist_setup_t &setup, const astring &icname) { const net_device_t_base_factory **p = &netregistry[0]; - while (p != NULL) + while (*p != NULL) { if (strcmp((*p)->classname(), classname) == 0) { @@ -1022,7 +1027,7 @@ net_device_t *net_create_device_by_classname(const astring &classname, netlist_s net_device_t *net_create_device_by_name(const astring &name, netlist_setup_t &setup, const astring &icname) { const net_device_t_base_factory **p = &netregistry[0]; - while (p != NULL) + while (*p != NULL) { if (strcmp((*p)->name(), name) == 0) { @@ -1035,3 +1040,4 @@ net_device_t *net_create_device_by_name(const astring &name, netlist_setup_t &se fatalerror("Class %s required for IC %s not found!\n", name.cstr(), icname.cstr()); return NULL; // appease code analysis } + diff --git a/src/emu/netlist/net_lib.h b/src/emu/netlist/devices/net_lib.h index d48642a9bd1..2eb66ad2324 100644 --- a/src/emu/netlist/net_lib.h +++ b/src/emu/netlist/devices/net_lib.h @@ -1,3 +1,5 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud /*************************************************************************** net_lib.h @@ -48,7 +50,11 @@ #ifndef NET_LIB_H #define NET_LIB_H -#include "machine/netlist.h" +#include "../nl_base.h" +#include "nld_signal.h" +#include "nld_system.h" + +#include "nld_7400.h" // this is a bad hack #define USE_OLD7493 (0) @@ -66,7 +72,7 @@ #define NETDEV_ANALOG_INPUT(_name) \ NET_REGISTER_DEV(netdev_analog_input, _name) #define NETDEV_CALLBACK(_name, _IN) \ - NET_REGISTER_DEV(netdev_analog_callback, _name) \ + NET_REGISTER_DEV(netdev_analog_callback, _name) \ NET_CONNECT(_name, IN, _IN) #define NETDEV_SWITCH2(_name, _i1, _i2) \ NET_REGISTER_DEV(nicMultiSwitch, _name) \ @@ -90,15 +96,10 @@ // TTL Logic chips // ---------------------------------------------------------------------------------------- -#define TTL_7400_NAND(_name, _I1, _I2) \ - NET_REGISTER_DEV(nic7400, _name) \ - NET_CONNECT(_name, I1, _I1) \ - NET_CONNECT(_name, I2, _I2) - #define TTL_7402_NOR(_name, _I1, _I2) \ NET_REGISTER_DEV(nic7402, _name) \ - NET_CONNECT(_name, I1, _I1) \ - NET_CONNECT(_name, I2, _I2) + NET_CONNECT(_name, A, _I1) \ + NET_CONNECT(_name, B, _I2) #define TTL_7404_INVERT(_name, _I1) \ NET_REGISTER_DEV(nic7404, _name) \ @@ -106,40 +107,40 @@ #define TTL_7410_NAND(_name, _I1, _I2, _I3) \ NET_REGISTER_DEV(nic7410, _name) \ - NET_CONNECT(_name, I1, _I1) \ - NET_CONNECT(_name, I2, _I2) \ - NET_CONNECT(_name, I3, _I3) + NET_CONNECT(_name, A, _I1) \ + NET_CONNECT(_name, B, _I2) \ + NET_CONNECT(_name, C, _I3) #define TTL_7420_NAND(_name, _I1, _I2, _I3, _I4) \ NET_REGISTER_DEV(nic7420, _name) \ - NET_CONNECT(_name, I1, _I1) \ - NET_CONNECT(_name, I2, _I2) \ - NET_CONNECT(_name, I3, _I3) \ - NET_CONNECT(_name, I4, _I4) + NET_CONNECT(_name, A, _I1) \ + NET_CONNECT(_name, B, _I2) \ + NET_CONNECT(_name, C, _I3) \ + NET_CONNECT(_name, D, _I4) #define TTL_7425_NOR(_name, _I1, _I2, _I3, _I4) \ NET_REGISTER_DEV(nic7425, _name) \ - NET_CONNECT(_name, I1, _I1) \ - NET_CONNECT(_name, I2, _I2) \ - NET_CONNECT(_name, I3, _I3) \ - NET_CONNECT(_name, I4, _I4) + NET_CONNECT(_name, A, _I1) \ + NET_CONNECT(_name, B, _I2) \ + NET_CONNECT(_name, C, _I3) \ + NET_CONNECT(_name, D, _I4) #define TTL_7427_NOR(_name, _I1, _I2, _I3) \ NET_REGISTER_DEV(nic7427, _name) \ - NET_CONNECT(_name, I1, _I1) \ - NET_CONNECT(_name, I2, _I2) \ - NET_CONNECT(_name, I3, _I3) + NET_CONNECT(_name, A, _I1) \ + NET_CONNECT(_name, B, _I2) \ + NET_CONNECT(_name, C, _I3) #define TTL_7430_NAND(_name, _I1, _I2, _I3, _I4, _I5, _I6, _I7, _I8) \ NET_REGISTER_DEV(nic7430, _name) \ - NET_CONNECT(_name, I1, _I1) \ - NET_CONNECT(_name, I2, _I2) \ - NET_CONNECT(_name, I3, _I3) \ - NET_CONNECT(_name, I4, _I4) \ - NET_CONNECT(_name, I5, _I5) \ - NET_CONNECT(_name, I6, _I6) \ - NET_CONNECT(_name, I7, _I7) \ - NET_CONNECT(_name, I8, _I8) + NET_CONNECT(_name, A, _I1) \ + NET_CONNECT(_name, B, _I2) \ + NET_CONNECT(_name, C, _I3) \ + NET_CONNECT(_name, D, _I4) \ + NET_CONNECT(_name, E, _I5) \ + NET_CONNECT(_name, F, _I6) \ + NET_CONNECT(_name, G, _I7) \ + NET_CONNECT(_name, H, _I8) #define TTL_7450_ANDORINVERT(_name, _I1, _I2, _I3, _I4) \ NET_REGISTER_DEV(nic7450, _name) \ @@ -324,13 +325,12 @@ NETLIB_DEVICE_WITH_PARAMS(nicNE555N_MSTABLE, net_param_t m_VL; ); -NETLIB_SIGNAL(nic7400, 2, 0, 0) -NETLIB_SIGNAL(nic7402, 2, 1, 0) -NETLIB_SIGNAL(nic7410, 3, 0, 0) -NETLIB_SIGNAL(nic7420, 4, 0, 0) -NETLIB_SIGNAL(nic7425, 4, 1, 0) -NETLIB_SIGNAL(nic7427, 3, 1, 0) -NETLIB_SIGNAL(nic7430, 8, 0, 0) +NETLIB_SIGNAL(nic7402, 2, 1, 0); +NETLIB_SIGNAL(nic7410, 3, 0, 0); +NETLIB_SIGNAL(nic7420, 4, 0, 0); +NETLIB_SIGNAL(nic7425, 4, 1, 0); +NETLIB_SIGNAL(nic7427, 3, 1, 0); +NETLIB_SIGNAL(nic7430, 8, 0, 0); NETLIB_DEVICE(nic7404, ttl_input_t m_I; @@ -356,7 +356,7 @@ NETLIB_SUBDEVICE(nic7474sub, ); NETLIB_DEVICE(nic7474, - nic7474sub sub; + NETLIB_NAME(nic7474sub) sub; ttl_input_t m_D; ttl_input_t m_clrQ; @@ -380,17 +380,16 @@ NETLIB_SUBDEVICE(nic74107Asub, ttl_output_t m_Q; ttl_output_t m_QQ; + netlist_sig_t m_Q1; + netlist_sig_t m_Q2; + netlist_sig_t m_F; - net_sig_t m_Q1; - net_sig_t m_Q2; - net_sig_t m_F; - - ATTR_HOT void newstate(const net_sig_t state); + ATTR_HOT void newstate(const netlist_sig_t state); ); NETLIB_DEVICE(nic74107A, - nic74107Asub sub; + NETLIB_NAME(nic74107Asub) sub; ttl_input_t m_J; ttl_input_t m_K; @@ -398,11 +397,11 @@ NETLIB_DEVICE(nic74107A, ); -class nic74107 : public nic74107A +class NETLIB_NAME(nic74107) : public NETLIB_NAME(nic74107A) { public: - nic74107() - : nic74107A() {} + NETLIB_NAME(nic74107) () + : NETLIB_NAME(nic74107A) () {} }; @@ -419,11 +418,12 @@ NETLIB_DEVICE(nic7493, ttl_input_t m_R1; ttl_input_t m_R2; - nic7493ff A; - nic7493ff B; - nic7493ff C; - nic7493ff D; + NETLIB_NAME(nic7493ff) A; + NETLIB_NAME(nic7493ff) B; + NETLIB_NAME(nic7493ff) C; + NETLIB_NAME(nic7493ff) D; ); + #else NETLIB_DEVICE(nic7493, ttl_input_t m_CLK; @@ -469,8 +469,8 @@ NETLIB_SUBDEVICE(nic9316_sub, ttl_input_t m_D; UINT8 m_cnt; - net_sig_t m_loadq; - net_sig_t m_ent; + netlist_sig_t m_loadq; + netlist_sig_t m_ent; ttl_output_t m_QA; ttl_output_t m_QB; @@ -480,7 +480,7 @@ NETLIB_SUBDEVICE(nic9316_sub, ); NETLIB_DEVICE(nic9316, - nic9316_sub sub; + NETLIB_NAME(nic9316_sub) sub; ttl_input_t m_ENP; ttl_input_t m_ENT; ttl_input_t m_CLRQ; @@ -543,7 +543,7 @@ NETLIB_SUBDEVICE(nic7448_sub, NETLIB_DEVICE(nic7448, - nic7448_sub sub; + NETLIB_NAME(nic7448_sub) sub; ttl_input_t m_LTQ; ttl_input_t m_BIQ; diff --git a/src/emu/netlist/devices/nld_7400.c b/src/emu/netlist/devices/nld_7400.c new file mode 100644 index 00000000000..977bd991dbc --- /dev/null +++ b/src/emu/netlist/devices/nld_7400.c @@ -0,0 +1,6 @@ +/* + * nld_7400.c + * + */ + + diff --git a/src/emu/netlist/devices/nld_7400.h b/src/emu/netlist/devices/nld_7400.h new file mode 100644 index 00000000000..078ceafd54b --- /dev/null +++ b/src/emu/netlist/devices/nld_7400.h @@ -0,0 +1,44 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * nld_7400.h + * + * DM7400: Quad 2-Input NAND Gates + * + * +--------------+ + * A1 |1 ++ 14| VCC + * B1 |2 13| B4 + * Y1 |3 12| A4 + * A2 |4 7400 11| Y4 + * B2 |5 10| B3 + * Y2 |6 9| A3 + * GND |7 8| Y3 + * +--------------+ + * __ + * Y = AB + * +---+---++---+ + * | A | B || Y | + * +===+===++===+ + * | 0 | 0 || 1 | + * | 0 | 1 || 1 | + * | 1 | 0 || 1 | + * | 1 | 1 || 0 | + * +---+---++---+ + * + * Naming conventions follow National Semiconductor datasheet + * + */ + +#include "nld_signal.h" + +#ifndef NLD_7400_H_ +#define NLD_7400_H_ + +#define TTL_7400_NAND(_name, _A, _B) \ + NET_REGISTER_DEV(7400, _name) \ + NET_CONNECT(_name, A, _A) \ + NET_CONNECT(_name, B, _B) + +NETLIB_SIGNAL(7400, 2, 0, 0); + +#endif /* NLD_7400_H_ */ diff --git a/src/emu/netlist/devices/nld_signal.h b/src/emu/netlist/devices/nld_signal.h new file mode 100644 index 00000000000..9119c0253a7 --- /dev/null +++ b/src/emu/netlist/devices/nld_signal.h @@ -0,0 +1,296 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * nld_signal.h + * + */ + +#ifndef NLD_SIGNAL_H_ +#define NLD_SIGNAL_H_ + +#include "../nl_base.h" + +// ---------------------------------------------------------------------------------------- +// MACROS +// ---------------------------------------------------------------------------------------- + +#define NETLIB_SIGNAL(_name, _num_input, _check, _invert) \ + class NETLIB_NAME(_name) : public net_signal_t<_num_input, _check, _invert> \ + { \ + public: \ + ATTR_COLD NETLIB_NAME(_name) () \ + : net_signal_t<_num_input, _check, _invert>() { } \ + } + +// ---------------------------------------------------------------------------------------- +// net_signal_t +// ---------------------------------------------------------------------------------------- + +template <int _numdev> +class net_signal_base_t : public net_device_t +{ +public: + net_signal_base_t() + : net_device_t(), m_active(1) { } + + ATTR_COLD void start() + { + const char *sIN[8] = { "I1", "I2", "I3", "I4", "I5", "I6", "I7", "I8" }; + + register_output("Q", m_Q); + for (int i=0; i < _numdev; i++) + { + register_input(sIN[i], m_i[i], net_input_t::INP_STATE_ACTIVE); + } + m_Q.initial(1); + } + +#if (USE_DEACTIVE_DEVICE) + ATTR_HOT void inc_active() + { + if (m_active == 0) + { + update(); + } + m_active++; + } + + ATTR_HOT void dec_active() + { + m_active--; + if (m_active == 0) + { + for (int i = 0; i< _numdev; i++) + m_i[i].inactivate(); + } + } +#endif + +public: + ttl_input_t m_i[_numdev]; + ttl_output_t m_Q; + INT8 m_active; +}; + + +template <int _numdev, int _check, int _invert> +class net_signal_t : public net_device_t +{ +public: + net_signal_t() + : net_device_t(), m_active(1) + { + m_Q.initial(1); + } + + ATTR_COLD void start() + { + const char *sIN[8] = { "A", "B", "C", "D", "E", "F", "G", "H" }; + + register_output("Q", m_Q); + for (int i=0; i < _numdev; i++) + { + register_input(sIN[i], m_i[i], net_input_t::INP_STATE_ACTIVE); + } + } + + #if (USE_DEACTIVE_DEVICE) + ATTR_HOT void inc_active() + { + if (m_active == 0) + { + update(); + } + m_active++; + } + + ATTR_HOT void dec_active() + { + m_active--; + if (m_active == 0) + { + for (int i = 0; i< _numdev; i++) + m_i[i].inactivate(); + } + } + #endif + + virtual void update() + { + static const netlist_time times[2] = { NLTIME_FROM_NS(22), NLTIME_FROM_NS(15) }; + int pos = -1; + + for (int i = 0; i< _numdev; i++) + { + this->m_i[i].activate(); + if (INPLOGIC(this->m_i[i]) == _check) + { + OUTLOGIC(this->m_Q, _check ^ (1 ^ _invert), times[_check]);// ? 15000 : 22000); + pos = i; + break; + } + } + if (pos >= 0) + { + for (int i = 0; i < _numdev; i++) + if (i != pos) + this->m_i[i].inactivate(); + } else + OUTLOGIC(this->m_Q,_check ^ (_invert), times[1-_check]);// ? 22000 : 15000); + } + +public: + ttl_input_t m_i[_numdev]; + ttl_output_t m_Q; + INT8 m_active; +}; + +#if 1 +template <int _check, int _invert> +class xx_net_signal_t: public net_device_t +{ +public: + xx_net_signal_t() + : net_device_t(), m_active(1) + { + m_Q.initial(1); + } + + ATTR_COLD void start() + { + const char *sIN[2] = { "A", "B" }; + + register_output("Q", m_Q); + for (int i=0; i < 2; i++) + { + register_input(sIN[i], m_i[i], net_input_t::INP_STATE_ACTIVE); + } + } + + #if (USE_DEACTIVE_DEVICE) + ATTR_HOT void inc_active() + { + if (m_active == 0) + { + update(); + } + m_active++; + } + + ATTR_HOT void dec_active() + { + m_active--; + if (m_active == 0) + { + m_i[0].inactivate(); + m_i[1].inactivate(); + } + } + #endif + + + ATTR_HOT ATTR_ALIGN void update() + { + const netlist_time times[2] = { NLTIME_FROM_NS(22), NLTIME_FROM_NS(15) }; + + int res = _invert ^ 1 ^_check; + m_i[0].activate(); + m_i[1].activate(); + if (INPLOGIC(m_i[0]) ^ _check) + { + if (INPLOGIC(m_i[1]) ^ _check) + { + res = _invert ^ _check; + } + else + m_i[0].inactivate(); + } else { + if (INPLOGIC(m_i[1]) ^ _check) + m_i[1].inactivate(); + } + OUTLOGIC(m_Q, res, times[(res & 1) ^ 1]);// ? 22000 : 15000); + } + +public: + ttl_input_t m_i[2]; + ttl_output_t m_Q; + INT8 m_active; + +}; +#endif + +// The following did not improve performance +#if 0 + +template <UINT8 _check, UINT8 _invert> +class net_signal_t<3, _check, _invert> : public net_device_t +{ +public: + net_signal_t() : net_device_t(), m_active(1) { } + + ATTR_COLD void start() + { + const char *sIN[3] = { "I1", "I2", "I3" }; + + register_output("Q", m_Q); + for (int i=0; i < 3; i++) + { + register_input(sIN[i], m_i[i], net_input_t::INP_STATE_ACTIVE); + } + m_Q.initial(1); + } + + ATTR_HOT ATTR_ALIGN void update() + { + const netlist_time times[2] = { NLTIME_FROM_NS(22), NLTIME_FROM_NS(15) }; + //const UINT8 res_tab[4] = {1, 1, 1, 0 }; + //const UINT8 ai1[4] = {0, 1, 0, 0 }; + //const UINT8 ai2[4] = {1, 0, 1, 0 }; + + UINT8 res = _invert ^ 1 ^_check; + m_i[0].activate(); + if (INPLOGIC(m_i[0]) ^ _check) + { + m_i[1].activate(); + if (INPLOGIC(m_i[1]) ^ _check) + { + m_i[2].activate(); + if (INPLOGIC(m_i[2]) ^ _check) + { + res = _invert ^ _check; + } + else + m_i[1].inactivate(); + } + else + { + if (INPLOGIC(m_i[2]) ^ _check) + m_i[2].inactivate(); + m_i[0].inactivate(); + } + } else { + if (INPLOGIC(m_i[1]) ^ _check) + m_i[1].inactivate(); + } + OUTLOGIC(m_Q, res, times[1 - res]);// ? 22000 : 15000); + } +public: + ttl_input_t m_i[3]; + ttl_output_t m_Q; + INT8 m_active; + +}; + +#endif + + +template <int _check, int _invert> +class net_signal_t<2, _check, _invert> : public xx_net_signal_t<_check, _invert> +{ +public: + net_signal_t() + : xx_net_signal_t<_check, _invert>() { } +}; + + +#endif /* NLD_SIGNAL_H_ */ diff --git a/src/emu/netlist/devices/nld_system.h b/src/emu/netlist/devices/nld_system.h new file mode 100644 index 00000000000..34cc4d99bc4 --- /dev/null +++ b/src/emu/netlist/devices/nld_system.h @@ -0,0 +1,82 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * nld_system.h + * + * netlist devices defined in the core + */ + +#ifndef NLD_SYSTEM_H_ +#define NLD_SYSTEM_H_ + +#include "../nl_setup.h" +#include "../nl_base.h" + +// ---------------------------------------------------------------------------------------- +// Macros +// ---------------------------------------------------------------------------------------- + +#define NETDEV_TTL_CONST(_name, _v) \ + NET_REGISTER_DEV(netdev_ttl_const, _name) \ + NETDEV_PARAM(_name.CONST, _v) + +#define NETDEV_ANALOG_CONST(_name, _v) \ + NET_REGISTER_DEV(netdev_analog_const, _name) \ + NETDEV_PARAM(_name.CONST, _v) + +// ---------------------------------------------------------------------------------------- +// netdev_*_const +// ---------------------------------------------------------------------------------------- + +NETLIB_DEVICE_WITH_PARAMS(netdev_ttl_const, + ttl_output_t m_Q; + net_param_t m_const; +); + +NETLIB_DEVICE_WITH_PARAMS(netdev_analog_const, + analog_output_t m_Q; + net_param_t m_const; +); + +// ---------------------------------------------------------------------------------------- +// netdev_mainclock +// ---------------------------------------------------------------------------------------- + +NETLIB_DEVICE_WITH_PARAMS(netdev_mainclock, + ttl_output_t m_Q; + + net_param_t m_freq; + netlist_time m_inc; + + ATTR_HOT inline static void mc_update(net_output_t &Q, const netlist_time curtime); +); + +// ---------------------------------------------------------------------------------------- +// netdev_callback +// ---------------------------------------------------------------------------------------- + +class NETLIB_NAME(netdev_analog_callback) : public net_device_t +{ +public: + NETLIB_NAME(netdev_analog_callback)() + : net_device_t() { } + + ATTR_COLD void start() + { + register_input("IN", m_in); + } + + ATTR_COLD void register_callback(netlist_output_delegate callback) + { + m_callback = callback; + } + + ATTR_HOT void update(); + + +private: + analog_input_t m_in; + netlist_output_delegate m_callback; +}; + +#endif /* NLD_SYSTEM_H_ */ diff --git a/src/emu/netlist/netlist.mak b/src/emu/netlist/netlist.mak index afe61c3b97b..76aa56236d4 100644 --- a/src/emu/netlist/netlist.mak +++ b/src/emu/netlist/netlist.mak @@ -17,5 +17,9 @@ NETLISTOBJ = $(EMUOBJ)/netlist # Core files #------------------------------------------------- -NETLISTOBJS+= $(NETLISTOBJ)/net_lib.o - +NETLISTOBJS+= \ + $(NETLISTOBJ)/nl_setup.o \ + $(NETLISTOBJ)/nl_base.o \ + $(NETLISTOBJ)/nl_parser.o \ + $(NETLISTOBJ)/devices/net_lib.o \ + diff --git a/src/emu/netlist/nl_base.c b/src/emu/netlist/nl_base.c new file mode 100644 index 00000000000..a784c64e3b7 --- /dev/null +++ b/src/emu/netlist/nl_base.c @@ -0,0 +1,435 @@ +/* + * nlbase.c + * + */ + +#include "nl_base.h" +#include "devices/nld_system.h" + + +// ---------------------------------------------------------------------------------------- +// netlist_base_t +// ---------------------------------------------------------------------------------------- + +netlist_base_t::netlist_base_t() + : m_mainclock(NULL), + m_time_ps(netlist_time::zero), + m_rem(0), + m_div(NETLIST_DIV) +{ +} + +netlist_base_t::~netlist_base_t() +{ +} + +ATTR_COLD void netlist_base_t::set_mainclock_dev(NETLIB_NAME(netdev_mainclock) *dev) +{ + m_mainclock = dev; +} + +ATTR_COLD void netlist_base_t::reset() +{ + m_time_ps = netlist_time::zero; + m_rem = 0; + m_queue.clear(); + if (m_mainclock != NULL) + m_mainclock->m_Q.set_time(netlist_time::zero); +} + + +void netlist_base_t::set_clock_freq(UINT64 clockfreq) +{ + m_div = netlist_time::from_hz(clockfreq).as_raw(); + m_rem = 0; + assert_always(m_div == NETLIST_DIV, "netlist: illegal clock!"); + NL_VERBOSE_OUT(("Setting clock %" I64FMT "d and divisor %d\n", clockfreq, m_div)); +} + +ATTR_HOT ATTR_ALIGN inline void netlist_base_t::update_time(const netlist_time t, INT32 &atime) +{ + if (NETLIST_DIV_BITS == 0) + { + const netlist_time delta = t - m_time_ps; + m_time_ps = t; + atime -= delta.as_raw(); + } else { + const netlist_time delta = t - m_time_ps + netlist_time::from_raw(m_rem); + m_time_ps = t; + m_rem = delta.as_raw() & NETLIST_MASK; + atime -= (delta.as_raw() >> NETLIST_DIV_BITS); + + // The folling is suitable for non-power of 2 m_divs ... + // atime -= divu_64x32_rem(delta.as_raw(), m_div, &m_rem); + } +} + +ATTR_HOT ATTR_ALIGN void netlist_base_t::process_queue(INT32 &atime) +{ + if (m_mainclock == NULL) + { + while ( (atime > 0) && (m_queue.is_not_empty())) + { + const queue_t::entry_t e = m_queue.pop(); + update_time(e.time(), atime); + + if (FATAL_ERROR_AFTER_NS) + printf("%s\n", e.object().netdev()->name().cstr()); + + e.object().update_devs(); + + add_to_stat(m_perf_out_processed, 1); + + if (FATAL_ERROR_AFTER_NS) + if (time() > NLTIME_FROM_NS(FATAL_ERROR_AFTER_NS)) + fatalerror("Stopped"); + } + + if (atime > 0) + { + m_time_ps += netlist_time::from_raw(atime * m_div); + atime = 0; + } + } else { + net_output_t &mcQ = m_mainclock->m_Q; + const netlist_time inc = m_mainclock->m_inc; + + while (atime > 0) + { + if (m_queue.is_not_empty()) + { + while (m_queue.peek().time() > mcQ.time()) + { + update_time(mcQ.time(), atime); + + NETLIB_NAME(netdev_mainclock)::mc_update(mcQ, time() + inc); + + } + const queue_t::entry_t e = m_queue.pop(); + + update_time(e.time(), atime); + + e.object().update_devs(); + + } else { + update_time(mcQ.time(), atime); + + NETLIB_NAME(netdev_mainclock)::mc_update(mcQ, time() + inc); + } + if (FATAL_ERROR_AFTER_NS) + if (time() > NLTIME_FROM_NS(FATAL_ERROR_AFTER_NS)) + fatalerror("Stopped"); + + add_to_stat(m_perf_out_processed, 1); + } + + if (atime > 0) + { + m_time_ps += netlist_time::from_raw(atime * m_div); + atime = 0; + } + } +} + +// ---------------------------------------------------------------------------------------- +// Default netlist elements ... +// ---------------------------------------------------------------------------------------- + + + +// ---------------------------------------------------------------------------------------- +// net_core_device_t +// ---------------------------------------------------------------------------------------- + +netlist_core_device_t::netlist_core_device_t() +: net_object_t(DEVICE) +{ +} + +ATTR_COLD void netlist_core_device_t::init(netlist_setup_t &setup, const astring &name) +{ + m_netlist = &setup.netlist(); + m_name = name; + +#if USE_DELEGATES +#if USE_PMFDELEGATES + void (netlist_core_device_t::* pFunc)() = &netlist_core_device_t::update; + static_update = reinterpret_cast<net_update_delegate>((this->*pFunc)); +#else + static_update = net_update_delegate(&netlist_core_device_t::update, "update", this); + // get the pointer to the member function +#endif +#endif + +} + +ATTR_COLD void net_device_t::init(netlist_setup_t &setup, const astring &name) +{ + netlist_core_device_t::init(setup, name); + m_setup = &setup; + start(); +} + + +netlist_core_device_t::~netlist_core_device_t() +{ +} + +// ---------------------------------------------------------------------------------------- +// net_device_t +// ---------------------------------------------------------------------------------------- + +ATTR_HOT ATTR_ALIGN const netlist_sig_t netlist_core_device_t::INPLOGIC_PASSIVE(logic_input_t &inp) +{ + if (inp.state() == net_input_t::INP_STATE_PASSIVE) + { + inp.activate(); + const netlist_sig_t ret = inp.Q(); + inp.inactivate(); + return ret; + } + else + return inp.Q(); + +} + +net_device_t::net_device_t() + : netlist_core_device_t(), + m_inputs(20), + m_setup(NULL), + m_variable_input_count(false) +{ +} + +net_device_t::~net_device_t() +{ + //printf("~net_device_t\n"); +} + +ATTR_COLD void net_device_t::register_sub(netlist_core_device_t &dev, const astring &name) +{ + dev.init(*m_setup, name); +} + +void net_device_t::register_output(netlist_core_device_t &dev, const astring &name, net_output_t &port) +{ + m_setup->register_output(*this, dev, name, port); +} + +void net_device_t::register_output(const astring &name, net_output_t &port) +{ + m_setup->register_output(*this,*this,name, port); +} + +void net_device_t::register_input(netlist_core_device_t &dev, const astring &name, net_input_t &inp, net_input_t::net_input_state type) +{ + m_setup->register_input(*this, dev, name, inp, type); +} + +void net_device_t::register_input(const astring &name, net_input_t &inp, net_input_t::net_input_state type) +{ + register_input(*this, name, inp, type); +} + +void net_device_t::register_link_internal(netlist_core_device_t &dev, net_input_t &in, net_output_t &out, net_input_t::net_input_state aState) +{ + in.set_output(out); + in.init_input(&dev, aState); + //if (in.state() != net_input_t::INP_STATE_PASSIVE) + out.register_con(in); +} + +void net_device_t::register_link_internal(net_input_t &in, net_output_t &out, net_input_t::net_input_state aState) +{ + register_link_internal(*this, in, out, aState); +} + +void net_device_t::register_param(netlist_core_device_t &dev, const astring &name, net_param_t ¶m, double initialVal) +{ + param.set_netdev(dev); + param.initial(initialVal); + m_setup->register_param(name, ¶m); +} + +void net_device_t::register_param(const astring &name, net_param_t ¶m, double initialVal) +{ + register_param(*this,name, param, initialVal); +} + +// ---------------------------------------------------------------------------------------- +// net_terminal_t +// ---------------------------------------------------------------------------------------- + +ATTR_COLD void net_terminal_t::init_terminal(netlist_core_device_t *dev) +{ + m_netdev = dev; + m_netlist = dev->netlist(); +} + +// ---------------------------------------------------------------------------------------- +// net_input_t +// ---------------------------------------------------------------------------------------- + +ATTR_COLD void net_input_t::init_input(netlist_core_device_t *dev, net_input_state astate) +{ + init_terminal(dev); + m_state = astate; +} + +// ---------------------------------------------------------------------------------------- +// net_output_t +// ---------------------------------------------------------------------------------------- + +net_output_t::net_output_t(int atype) + : net_terminal_t(atype) + , m_low_V(0.0) + , m_high_V(0.0) + , m_last_Q(0) + , m_Q(0) + , m_new_Q(0) + , m_Q_analog(0.0) + , m_new_Q_analog(0.0) + , m_num_cons(0) + , m_time(netlist_time::zero) + , m_active(0) + , m_in_queue(2) +{ + //m_cons = global_alloc_array(net_input_t *, OUTPUT_MAX_CONNECTIONS); +} + +ATTR_HOT inline void net_output_t::update_dev(const net_input_t *inp, const UINT32 mask) +{ + if ((inp->state() & mask) != 0) + { + ATTR_UNUSED netlist_core_device_t *netdev = inp->netdev(); + begin_timing(netdev->total_time); + inc_stat(netdev->stat_count); + netdev->update_dev(); + end_timing(netdev()->total_time); + } +} + +ATTR_HOT inline void net_output_t::update_devs() +{ + + assert(m_num_cons != 0); + + const UINT32 masks[4] = { 1, 5, 3, 1 }; + m_Q = m_new_Q; + m_Q_analog = m_new_Q_analog; + m_in_queue = 2; /* mark as taken ... */ + + const UINT32 mask = masks[ (m_last_Q << 1) | m_Q ]; + + switch (m_num_cons) + { + case 2: + update_dev(m_cons[1], mask); + case 1: + update_dev(m_cons[0], mask); + break; + default: + { + for (int i=0; i < m_num_cons; i++) + update_dev(m_cons[i], mask); + } + break; + } + + m_last_Q = m_Q; +} + +ATTR_COLD void net_output_t::register_con(net_input_t &input) +{ + int i; + if (m_num_cons >= OUTPUT_MAX_CONNECTIONS) + fatalerror("Connections exceeded for %s\n", netdev()->name().cstr()); + + /* keep similar devices together */ + for (i = 0; i < m_num_cons; i++) + if (m_cons[i]->netdev() == input.netdev()) + break; + + for (int j = m_num_cons; j > i; j--) + m_cons[j] = m_cons[j - 1]; + + m_cons[i] = &input; + m_num_cons++; + if (input.state() != net_input_t::INP_STATE_PASSIVE) + m_active++; +} + +// ---------------------------------------------------------------------------------------- +// netdev_const +// ---------------------------------------------------------------------------------------- + +NETLIB_START(netdev_ttl_const) +{ + register_output("Q", m_Q); + register_param("CONST", m_const, 0.0); +} + +NETLIB_UPDATE(netdev_ttl_const) +{ +} + +NETLIB_UPDATE_PARAM(netdev_ttl_const) +{ + OUTLOGIC(m_Q, m_const.ValueInt(), NLTIME_IMMEDIATE); +} + +NETLIB_START(netdev_analog_const) +{ + register_output("Q", m_Q); + register_param("CONST", m_const, 0.0); +} + +NETLIB_UPDATE(netdev_analog_const) +{ +} + +NETLIB_UPDATE_PARAM(netdev_analog_const) +{ + m_Q.initial(m_const.Value()); +} + +NETLIB_UPDATE(netdev_analog_callback) +{ + // FIXME: Remove after device cleanup + if (!m_callback.isnull()) + m_callback(INPANALOG(m_in)); +} + +// license:GPL-2.0+ +// copyright-holders:Couriersud +// ---------------------------------------------------------------------------------------- +// netdev_mainclock +// ---------------------------------------------------------------------------------------- + +ATTR_HOT inline void NETLIB_NAME(netdev_mainclock)::mc_update(net_output_t &Q, const netlist_time curtime) +{ + Q.m_new_Q = !Q.m_new_Q; + Q.set_time(curtime); + Q.update_devs(); +} + +ATTR_COLD NETLIB_START(netdev_mainclock) +{ + register_output("Q", m_Q); + + register_param("FREQ", m_freq, 7159000.0 * 5); + m_inc = netlist_time::from_hz(m_freq.Value()*2); + +} + +ATTR_HOT NETLIB_UPDATE_PARAM(netdev_mainclock) +{ + m_inc = netlist_time::from_hz(m_freq.Value()*2); +} + +ATTR_HOT NETLIB_UPDATE(netdev_mainclock) +{ + // this is only called during setup ... + m_Q.m_new_Q = !m_Q.m_new_Q; + m_Q.set_time(m_netlist->time() + m_inc); +} diff --git a/src/emu/netlist/nl_base.h b/src/emu/netlist/nl_base.h new file mode 100644 index 00000000000..713e94572e2 --- /dev/null +++ b/src/emu/netlist/nl_base.h @@ -0,0 +1,811 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * nlbase.h + * + */ + +#ifndef NLBASE_H_ +#define NLBASE_H_ + +#include "nl_config.h" +#include "nl_lists.h" +#include "nl_time.h" + +// ---------------------------------------------------------------------------------------- +// Type definitions +// ---------------------------------------------------------------------------------------- + +class netlist_core_device_t; + +#if USE_DELEGATES +#if USE_PMFDELEGATES +typedef void (*net_update_delegate)(netlist_core_device_t *); +#else +typedef delegate<void ()> net_update_delegate; +#endif +#endif + +//============================================================ +// MACROS / netlist devices +//============================================================ + +#define NETLIB_NAME(_chip) nld_ ## _chip + +#define NETLIB_NAME_STR_S(_s) # _s +#define NETLIB_NAME_STR(_chip) NETLIB_NAME_STR_S(nld_ ## _chip) + +#define NETLIB_UPDATE(_chip) ATTR_HOT ATTR_ALIGN void NETLIB_NAME(_chip) :: update(void) +#define NETLIB_START(_chip) ATTR_COLD void NETLIB_NAME(_chip) :: start(void) +//#define NETLIB_CONSTRUCTOR(_chip) ATTR_COLD _chip :: _chip (netlist_setup_t &setup, const char *name) +// : net_device_t(setup, name) + +#define NETLIB_UPDATE_PARAM(_chip) ATTR_HOT ATTR_ALIGN void NETLIB_NAME(_chip) :: update_param(void) +#define NETLIB_FUNC_VOID(_chip, _name, _params) ATTR_HOT ATTR_ALIGN inline void NETLIB_NAME(_chip) :: _name _params + +#define NETLIB_DEVICE(_name, _priv) \ + class NETLIB_NAME(_name) : public net_device_t \ + { \ + public: \ + NETLIB_NAME(_name) () \ + : net_device_t() { } \ + protected: \ + ATTR_HOT void update(); \ + ATTR_HOT void start(); \ + _priv \ + } + +#define NETLIB_SUBDEVICE(_name, _priv) \ + class NETLIB_NAME(_name) : public netlist_core_device_t \ + { \ + public: \ + NETLIB_NAME(_name) () \ + : netlist_core_device_t() \ + { } \ + /*protected:*/ \ + ATTR_HOT void update(); \ + _priv \ + } + +#define NETLIB_DEVICE_WITH_PARAMS(_name, _priv) \ + class NETLIB_NAME(_name) : public net_device_t \ + { \ + public: \ + NETLIB_NAME(_name) () \ + : net_device_t() { } \ + ATTR_HOT void update_param(); \ + ATTR_HOT void update(); \ + ATTR_HOT void start(); \ + /* protected: */ \ + _priv \ + } + +// ---------------------------------------------------------------------------------------- +// forward definitions +// ---------------------------------------------------------------------------------------- + +class net_output_t; +class net_param_t; +class netlist_setup_t; +class netlist_base_t; + + +// ---------------------------------------------------------------------------------------- +// net_object_t +// ---------------------------------------------------------------------------------------- + +class net_object_t +{ +public: + enum type_t { + INPUT = 0, + OUTPUT = 1, + DEVICE = 2, + PARAM = 3, + TERMINAL = 4, + NET_ANALOG = 5, + NET_DIGITAL = 6, + TYPE_MASK = 0x0f, + SIGNAL_DIGITAL = 0x00, + SIGNAL_ANALOG = 0x10, + SIGNAL_MASK = 0x10, + }; + + net_object_t(int atype) + : m_objtype(atype) {} + + virtual ~net_object_t() {} + + ATTR_HOT inline int object_type() const { return m_objtype; } + ATTR_HOT inline int object_type(const UINT32 mask) const { return m_objtype & mask; } + +private: + int m_objtype; +}; + +// ---------------------------------------------------------------------------------------- +// net_terminal_t +// ---------------------------------------------------------------------------------------- + +class net_terminal_t : public net_object_t +{ +public: + + net_terminal_t(const int atype) + : net_object_t(atype) + , m_netdev(NULL) + , m_netlist(NULL) + {} + + ATTR_COLD void init_terminal(netlist_core_device_t *dev); + ATTR_HOT inline netlist_core_device_t * RESTRICT netdev() const { return m_netdev; } + ATTR_HOT inline netlist_base_t * RESTRICT netlist() const { return m_netlist; } + +private: + netlist_core_device_t * RESTRICT m_netdev; + netlist_base_t * RESTRICT m_netlist; +}; + + +// ---------------------------------------------------------------------------------------- +// net_input_t +// ---------------------------------------------------------------------------------------- + +class net_input_t : public net_terminal_t +{ +public: + + enum net_input_state { + INP_STATE_PASSIVE = 0, + INP_STATE_ACTIVE = 1, + INP_STATE_HL = 2, + INP_STATE_LH = 4, + }; + + ATTR_COLD net_input_t(const int atype) + : net_terminal_t(atype) + , m_low_thresh_V(0) + , m_high_thresh_V(0) + , m_state(INP_STATE_ACTIVE) + , m_output(NULL) + {} + + ATTR_COLD void init_input(netlist_core_device_t *dev, net_input_state astate = INP_STATE_ACTIVE); + + ATTR_HOT inline net_output_t * RESTRICT output() const { return m_output; } + ATTR_HOT inline const bool is_state(const net_input_state astate) const { return (m_state == astate); } + ATTR_HOT inline const net_input_state state() const { return m_state; } + + ATTR_COLD void set_output(net_output_t &aout) { m_output = &aout; } + ATTR_HOT inline void inactivate(); + ATTR_HOT inline void activate(); + ATTR_HOT inline void activate_hl(); + ATTR_HOT inline void activate_lh(); + + double m_low_thresh_V; + double m_high_thresh_V; + +private: + net_input_state m_state; + net_output_t * RESTRICT m_output; +}; + +// ---------------------------------------------------------------------------------------- +// logic_input_t +// ---------------------------------------------------------------------------------------- + +class logic_input_t : public net_input_t +{ +public: + logic_input_t() + : net_input_t(INPUT | SIGNAL_DIGITAL) + { + // default to TTL + m_low_thresh_V = 0.8; + m_high_thresh_V = 2.0; + } + + ATTR_HOT inline const netlist_sig_t Q() const; + ATTR_HOT inline const netlist_sig_t last_Q() const; + + ATTR_COLD inline void set_thresholds(const double low, const double high) + { + m_low_thresh_V = low; + m_high_thresh_V = high; + } +}; + +// ---------------------------------------------------------------------------------------- +// ttl_input_t +// ---------------------------------------------------------------------------------------- + +class ttl_input_t : public logic_input_t +{ +public: + ttl_input_t() + : logic_input_t() { set_thresholds(0.8 , 2.0); } +}; + +class analog_input_t : public net_input_t +{ +public: + analog_input_t() + : net_input_t(INPUT | SIGNAL_ANALOG) { } + + ATTR_HOT inline const bool is_highz() const; + ATTR_HOT inline const double Q_Analog() const; +}; + +//#define INPVAL(_x) (_x).Q() + +// ---------------------------------------------------------------------------------------- +// net_output_t +// ---------------------------------------------------------------------------------------- + +class NETLIB_NAME(netdev_mainclock); + +class net_output_t : public net_terminal_t +{ +public: + + net_output_t(int atype); + + friend const netlist_sig_t logic_input_t::Q() const; + friend const double analog_input_t::Q_Analog() const; + friend const bool analog_input_t::is_highz() const; + friend class NETLIB_NAME(netdev_mainclock); + + ATTR_HOT inline const netlist_sig_t last_Q() const { return m_last_Q; } + ATTR_HOT inline const netlist_sig_t new_Q() const { return m_new_Q; } + + ATTR_COLD void register_con(net_input_t &inp); + + ATTR_HOT inline void update_devs(); + + ATTR_HOT inline void inc_active(); + ATTR_HOT inline void dec_active(); + + ATTR_HOT inline const int active_count() const { return m_active; } + ATTR_HOT inline const netlist_time time() const { return m_time; } + ATTR_HOT inline void set_time(const netlist_time ntime) { m_time = ntime; } + + double m_low_V; + double m_high_V; + +protected: + + /* prohibit use in device functions + * current (pending) state can be inquired using new_Q() + */ + ATTR_HOT inline const netlist_sig_t Q() const + { + assert(object_type(SIGNAL_MASK) == SIGNAL_DIGITAL); + return m_Q; + } + ATTR_HOT inline const double Q_Analog() const + { + assert(object_type(SIGNAL_MASK) == SIGNAL_ANALOG); + return m_Q_analog; + } + + ATTR_HOT inline void push_to_queue(const netlist_time &delay); + + netlist_sig_t m_last_Q; + netlist_sig_t m_Q; + netlist_sig_t m_new_Q; + + double m_Q_analog; + double m_new_Q_analog; + + UINT32 m_num_cons; +private: + ATTR_HOT void update_dev(const net_input_t *inp, const UINT32 mask); + + netlist_time m_time; + + INT32 m_active; + + UINT32 m_in_queue; /* 0: not in queue, 1: in queue, 2: last was taken */ + + net_input_t * RESTRICT m_cons[OUTPUT_MAX_CONNECTIONS]; +}; + + +class logic_output_t : public net_output_t +{ +public: + + logic_output_t() + : net_output_t(OUTPUT | SIGNAL_DIGITAL) + { + // Default to TTL + m_low_V = 0.1; // these depend on sinked/sourced current. Values should be suitable for typical applications. + m_high_V = 4.8; + } + + ATTR_COLD void initial(const netlist_sig_t val) { m_Q = val; m_new_Q = val; m_last_Q = !val; } + + ATTR_HOT inline void set_Q(const netlist_sig_t newQ, const netlist_time &delay) + { + if (EXPECTED(newQ != m_new_Q)) + { + m_new_Q = newQ; + if (m_num_cons) + push_to_queue(delay); + } + } + + ATTR_COLD inline void set_levels(const double low, const double high) + { + m_low_V = low; + m_high_V = high; + } +}; + +class ttl_output_t : public logic_output_t +{ +public: + + ttl_output_t() + : logic_output_t() + { set_levels(0.3, 3.4); } + +}; + +class analog_output_t : public net_output_t +{ +public: + + analog_output_t() + : net_output_t(OUTPUT | SIGNAL_ANALOG) { } + + ATTR_COLD void initial(const double val) { m_Q_analog = val; m_new_Q_analog = val; } + + ATTR_HOT inline void set_Q(const double newQ, const netlist_time &delay) + { + if (newQ != m_new_Q_analog) + { + m_new_Q_analog = newQ; + push_to_queue(delay); + } + } + +}; + +// ---------------------------------------------------------------------------------------- +// net_device_t +// ---------------------------------------------------------------------------------------- + +class netlist_core_device_t : public net_object_t +{ +public: + + netlist_core_device_t(); + + virtual ~netlist_core_device_t(); + + ATTR_COLD virtual void init(netlist_setup_t &setup, const astring &name); + + ATTR_COLD const astring &name() const { return m_name; } + + ATTR_HOT virtual void update_param() {} + + ATTR_HOT const netlist_sig_t INPLOGIC_PASSIVE(logic_input_t &inp); + + ATTR_HOT inline void update_dev() + { +#if USE_DELEGATES +#if USE_PMFDELEGATES + static_update(this); +#else + static_update(); +#endif +#else + update(); +#endif + } + + ATTR_HOT inline const netlist_sig_t INPLOGIC(const logic_input_t &inp) const + { + assert(inp.state() != net_input_t::INP_STATE_PASSIVE); + return inp.Q(); + } + + ATTR_HOT inline void OUTLOGIC(logic_output_t &out, const netlist_sig_t val, const netlist_time &delay) + { + out.set_Q(val, delay); + } + + ATTR_HOT inline bool INP_HL(const logic_input_t &inp) const + { + return ((inp.last_Q() & !inp.Q()) == 1); + } + + ATTR_HOT inline bool INP_LH(const logic_input_t &inp) const + { + return ((!inp.last_Q() & inp.Q()) == 1); + } + + ATTR_HOT inline const double INPANALOG(const analog_input_t &inp) const { return inp.Q_Analog(); } + + ATTR_HOT inline void OUTANALOG(analog_output_t &out, const double val, const netlist_time &delay) + { + out.set_Q(val, delay); + } + + ATTR_HOT inline netlist_base_t *netlist() const { return m_netlist; } + + ATTR_HOT virtual void inc_active() { } + + ATTR_HOT virtual void dec_active() { /*printf("DeActivate %s\n", m_name);*/ } + + /* stats */ + osd_ticks_t total_time; + INT32 stat_count; + +#if USE_DELEGATES + net_update_delegate static_update; +#endif + +protected: + + ATTR_HOT virtual void update() { } + ATTR_HOT virtual void start() { } + + netlist_base_t * RESTRICT m_netlist; + +private: + + astring m_name; +}; + + +class net_device_t : public netlist_core_device_t +{ +public: + + net_device_t(); + + virtual ~net_device_t(); + + ATTR_COLD virtual void init(netlist_setup_t &setup, const astring &name); + + ATTR_COLD const netlist_setup_t *setup() const { return m_setup; } + + ATTR_COLD bool variable_input_count() { return m_variable_input_count; } + + ATTR_COLD void register_sub(netlist_core_device_t &dev, const astring &name); + + ATTR_COLD void register_output(const astring &name, net_output_t &out); + ATTR_COLD void register_output(netlist_core_device_t &dev, const astring &name, net_output_t &out); + + ATTR_COLD void register_input(const astring &name, net_input_t &in, net_input_t::net_input_state state = net_input_t::INP_STATE_ACTIVE); + ATTR_COLD void register_input(netlist_core_device_t &dev, const astring &name, net_input_t &in, net_input_t::net_input_state state = net_input_t::INP_STATE_ACTIVE); + + ATTR_COLD void register_link_internal(net_input_t &in, net_output_t &out, net_input_t::net_input_state aState); + ATTR_COLD void register_link_internal(netlist_core_device_t &dev, net_input_t &in, net_output_t &out, net_input_t::net_input_state aState); + + netlist_list_t<astring> m_inputs; + +protected: + + virtual void update() { } + ATTR_HOT virtual void start() { } + + ATTR_COLD void register_param(const astring &sname, net_param_t ¶m, const double initialVal = 0.0); + ATTR_COLD void register_param(netlist_core_device_t &dev, const astring &sname, net_param_t ¶m, const double initialVal = 0.0); + + netlist_setup_t *m_setup; + bool m_variable_input_count; + +private: +}; + +class net_param_t +{ +public: + net_param_t() + : m_param(0.0) + , m_netdev(NULL) + { } + + inline void setTo(const double param) { m_param = param; m_netdev->update_param(); } + inline void setTo(const int param) { m_param = param; m_netdev->update_param(); } + inline void initial(const double val) { m_param = val; } + inline void initial(const int val) { m_param = val; } + + ATTR_HOT inline double Value() const { return m_param; } + ATTR_HOT inline int ValueInt() const { return (int) m_param; } + + ATTR_HOT inline netlist_core_device_t &netdev() const { return *m_netdev; } + void set_netdev(netlist_core_device_t &dev) { m_netdev = &dev; } + +private: + + double m_param; + netlist_core_device_t *m_netdev; +}; + + + +class netdev_mainclock; + +// ---------------------------------------------------------------------------------------- +// netlist_base_t +// ---------------------------------------------------------------------------------------- + +class netlist_base_t +{ +public: + + typedef netlist_timed_queue1<net_output_t, netlist_time, 512> queue_t; + + netlist_base_t(); + virtual ~netlist_base_t(); + + void set_clock_freq(UINT64 clockfreq); + + ATTR_HOT inline void push_to_queue(net_output_t &out, const netlist_time &attime) + { + m_queue.push(queue_t::entry_t(attime, out)); + } + + ATTR_HOT void process_queue(INT32 &atime); + + ATTR_HOT inline const netlist_time &time() const { return m_time_ps; } + + ATTR_COLD void set_mainclock_dev(NETLIB_NAME(netdev_mainclock) *dev); + + ATTR_COLD void reset(); + + // FIXME: should'nt be public + queue_t m_queue; + +protected: + // performance + int m_perf_out_processed; + int m_perf_inp_processed; + int m_perf_inp_active; + +private: + NETLIB_NAME(netdev_mainclock) *m_mainclock; + netlist_time m_time_ps; + UINT32 m_rem; + UINT32 m_div; + + + ATTR_HOT void update_time(const netlist_time t, INT32 &atime); + +}; + +// ---------------------------------------------------------------------------------------- +// netdev_a_to_d +// ---------------------------------------------------------------------------------------- + +class netdev_a_to_d_proxy : public net_device_t +{ +public: + netdev_a_to_d_proxy(net_input_t &in_proxied) + : net_device_t() + { + assert(in_proxied.object_type(SIGNAL_MASK) == SIGNAL_DIGITAL); + m_I.m_high_thresh_V = in_proxied.m_high_thresh_V; + m_I.m_low_thresh_V = in_proxied.m_low_thresh_V; + } + + virtual ~netdev_a_to_d_proxy() {} + + analog_input_t m_I; + ttl_output_t m_Q; + +protected: + void start() + { + m_I.init_input(this); + + m_Q.init_terminal(this); + m_Q.initial(1); + } + + ATTR_HOT ATTR_ALIGN void update() + { + if (m_I.Q_Analog() > m_I.m_high_thresh_V) + OUTLOGIC(m_Q, 1, NLTIME_FROM_NS(1)); + else if (m_I.Q_Analog() < m_I.m_low_thresh_V) + OUTLOGIC(m_Q, 0, NLTIME_FROM_NS(1)); + } + +}; + +// ---------------------------------------------------------------------------------------- +// netdev_d_to_a +// ---------------------------------------------------------------------------------------- + +class netdev_d_to_a_proxy : public net_device_t +{ +public: + netdev_d_to_a_proxy(net_output_t &out_proxied) + : net_device_t() + { + assert(out_proxied.object_type(SIGNAL_MASK) == SIGNAL_DIGITAL); + m_low_V = out_proxied.m_low_V; + m_high_V = out_proxied.m_high_V; + } + + virtual ~netdev_d_to_a_proxy() {} + + ttl_input_t m_I; + analog_output_t m_Q; + +protected: + void start() + { + m_I.init_input(this); + m_Q.init_terminal(this); + m_Q.initial(0); + } + + ATTR_HOT ATTR_ALIGN void update() + { + OUTANALOG(m_Q, INPLOGIC(m_I) ? m_high_V : m_low_V, NLTIME_FROM_NS(1)); + } + +private: + double m_low_V; + double m_high_V; +}; + + +// ---------------------------------------------------------------------------------------- +// Inline implementations +// ---------------------------------------------------------------------------------------- + +ATTR_HOT inline void net_input_t::inactivate() +{ + if (m_state != INP_STATE_PASSIVE) + { + m_state = INP_STATE_PASSIVE; + m_output->dec_active(); + } +} + +ATTR_HOT inline void net_input_t::activate() +{ + if (m_state == INP_STATE_PASSIVE) + { + m_output->inc_active(); + m_state = INP_STATE_ACTIVE; + } +} + +ATTR_HOT inline void net_input_t::activate_hl() +{ + if (m_state == INP_STATE_PASSIVE) + { + m_output->inc_active(); + m_state = INP_STATE_HL; + } +} + +ATTR_HOT inline void net_input_t::activate_lh() +{ + if (m_state == INP_STATE_PASSIVE) + { + m_output->inc_active(); + m_state = INP_STATE_LH; + } +} + + +ATTR_HOT inline void net_output_t::push_to_queue(const netlist_time &delay) +{ + // 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) + { + //m_in_queue = 1; /* pending */ + netlist()->push_to_queue(*this, m_time); + } +} + +ATTR_HOT inline void net_output_t::inc_active() +{ + m_active++; + +#if USE_DEACTIVE_DEVICE + if (m_active == 1 && m_in_queue > 0) + { + m_last_Q = m_Q; + netdev()->inc_active(); + m_Q = m_new_Q; + } +#endif + + if (EXPECTED(m_active == 1 && m_in_queue == 0)) + { + if (EXPECTED(m_time > netlist()->time())) + { + m_in_queue = 1; /* pending */ + netlist()->push_to_queue(*this, m_time); + } + else + { + m_Q = m_last_Q = m_new_Q; + m_Q_analog = m_new_Q_analog; + m_in_queue = 2; + } + } +} + +ATTR_HOT inline void net_output_t::dec_active() +{ + m_active--; +#if (USE_DEACTIVE_DEVICE) + if (m_active == 0) + netdev()->dec_active(); +#endif +} + +ATTR_HOT inline const netlist_sig_t logic_input_t::Q() const +{ + return output()->Q(); +} + +ATTR_HOT inline const netlist_sig_t logic_input_t::last_Q() const +{ + return output()->last_Q(); +} + +ATTR_HOT inline const double analog_input_t::Q_Analog() const +{ + return output()->Q_Analog(); +} + +ATTR_HOT inline const bool analog_input_t::is_highz() const +{ + return (output()->Q_Analog() == NETLIST_HIGHIMP_V); +} + +// ---------------------------------------------------------------------------------------- +// net_dev class factory +// ---------------------------------------------------------------------------------------- + +class net_device_t_base_factory +{ +public: + net_device_t_base_factory(const astring &name, const astring &classname) + : m_name(name), m_classname(classname) + {} + + virtual ~net_device_t_base_factory() {} + + virtual net_device_t *Create() const = 0; + + const astring &name() const { return m_name; } + const astring &classname() const { return m_classname; } +protected: + astring m_name; /* device name */ + astring m_classname; /* device class name */ +}; + +template <class C> +class net_device_t_factory : public net_device_t_base_factory +{ +public: + net_device_t_factory(const astring &name, const astring &classname) + : net_device_t_base_factory(name, classname) { } + + net_device_t *Create() const + { + net_device_t *r = new C(); + //r->init(setup, name); + return r; + } +}; + +net_device_t *net_create_device_by_classname(const astring &classname, netlist_setup_t &setup, const astring &icname); +net_device_t *net_create_device_by_name(const astring &name, netlist_setup_t &setup, const astring &icname); + + +#endif /* NLBASE_H_ */ diff --git a/src/emu/netlist/nl_config.h b/src/emu/netlist/nl_config.h new file mode 100644 index 00000000000..91bc758193c --- /dev/null +++ b/src/emu/netlist/nl_config.h @@ -0,0 +1,103 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * nlconfig.h + * + */ + +#ifndef NLCONFIG_H_ +#define NLCONFIG_H_ + +/* FIXME: at some time, make it compile on it's own */ + +#include "emu.h" + +//============================================================ +// SETUP +//============================================================ + +#define USE_DELEGATES (0) +/* + * The next options needs -Wno-pmf-conversions to compile and gcc + * This is intended for non-mame usage. + * + */ +#define USE_PMFDELEGATES (0) + +// Next if enabled adds 20% performance ... but is not guaranteed to be absolutely timing correct. +#define USE_DEACTIVE_DEVICE (0) + +#define OUTPUT_MAX_CONNECTIONS (48) + +// Use nano-second resolution - Sufficient for now +#define NETLIST_INTERNAL_RES (U64(1000000000)) +#define NETLIST_DIV_BITS (0) +//#define NETLIST_INTERNAL_RES (U64(1000000000000)) +//#define NETLIST_DIV_BITS (10) +#define NETLIST_DIV (U64(1) << NETLIST_DIV_BITS) +#define NETLIST_MASK (NETLIST_DIV-1) +#define NETLIST_CLOCK (NETLIST_INTERNAL_RES / NETLIST_DIV) + +#define NETLIST_HIGHIMP_V (1.23456e20) /* some voltage we should never see */ + +typedef UINT8 netlist_sig_t; + +/* FIXME: We need a different solution to output delegates ! + * More something like a callback object + */ + +typedef delegate<void (const double)> netlist_output_delegate; + +//============================================================ +// DEBUGGING +//============================================================ + +#define NL_VERBOSE (0) +#define NL_KEEP_STATISTICS (0) +#define FATAL_ERROR_AFTER_NS (0) //(1000) + +#if (NL_VERBOSE) + #define NL_VERBOSE_OUT(x) printf x +#else + #define NL_VERBOSE_OUT(x) +#endif + +//============================================================ +// MACROS +//============================================================ + +#if NL_KEEP_STATISTICS +#define add_to_stat(v,x) do { v += (x); } while (0) +#define inc_stat(v) add_to_stat(v, 1) +#define begin_timing(v) do { (v) -= get_profile_ticks(); } while (0) +#define end_timing(v) do { (v) += get_profile_ticks(); } while (0) +#else +#define add_to_stat(v,x) do { } while (0) +#define inc_stat(v) add_to_stat(v, 1) +#define begin_timing(v) do { } while (0) +#define end_timing(v) do { } while (0) +#endif + +// Compiling without mame ? + +#ifndef ATTR_HOT +#warning ATTR_HOT not defined +#define ATTR_HOT +#endif + +#ifndef ATTR_COLD +#define ATTR_COLD +#endif + +#if defined(__GNUC__) && (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) +#if !defined(__ppc__) && !defined (__PPC__) && !defined(__ppc64__) && !defined(__PPC64__) +#define ATTR_ALIGN __attribute__ ((aligned(128))) +#else +#define ATTR_ALIGN +#endif +#else +#define ATTR_ALIGN +#endif + + +#endif /* NLCONFIG_H_ */ diff --git a/src/emu/netlist/nl_lists.h b/src/emu/netlist/nl_lists.h new file mode 100644 index 00000000000..cb437df14c2 --- /dev/null +++ b/src/emu/netlist/nl_lists.h @@ -0,0 +1,134 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * nllists.h + * + */ + +#ifndef NLLISTS_H_ +#define NLLISTS_H_ + +#include "nl_config.h" + +// ---------------------------------------------------------------------------------------- +// netlist_list_t: a simple list +// ---------------------------------------------------------------------------------------- + + +template <class _ListClass> +struct netlist_list_t +{ +public: + ATTR_COLD netlist_list_t(int numElements) + { + m_num_elements = numElements; + m_list = new _ListClass[m_num_elements]; + m_ptr = m_list; + m_ptr--; + } + ATTR_COLD ~netlist_list_t() + { + delete[] m_list; + } + ATTR_HOT inline void add(const _ListClass elem) + { + assert(m_ptr-m_list <= m_num_elements - 1); + + *(++m_ptr) = elem; + } + ATTR_HOT inline _ListClass *first() { return &m_list[0]; } + ATTR_HOT inline _ListClass *last() { return m_ptr; } + ATTR_HOT inline _ListClass *item(int i) { return &m_list[i]; } + ATTR_HOT inline int count() const { return m_ptr - m_list + 1; } + ATTR_HOT inline bool empty() { return (m_ptr < m_list); } + ATTR_HOT inline void clear() { m_ptr = m_list - 1; } +private: + _ListClass * m_ptr; + _ListClass * m_list; + int m_num_elements; + //_ListClass m_list[_NumElements]; +}; + +// ---------------------------------------------------------------------------------------- +// timed queue +// ---------------------------------------------------------------------------------------- + +template <class _Element, class _Time, int _Size> +class netlist_timed_queue1 +{ +public: + + struct entry_t + { + public: + inline entry_t() + : m_time(), m_object(NULL) {} + inline entry_t(const _Time atime, _Element &elem) : m_time(atime), m_object(&elem) {} + ATTR_HOT inline const _Time &time() const { return m_time; } + ATTR_HOT inline _Element & object() const { return *m_object; } + private: + _Time m_time; + _Element *m_object; + }; + + netlist_timed_queue1() + { + //m_list = global_alloc_array(entry_t, SIZE); + clear(); + } + + ATTR_HOT inline bool is_empty() const { return (m_end == &m_list[0]); } + ATTR_HOT inline bool is_not_empty() const { return (m_end > &m_list[0]); } + + ATTR_HOT ATTR_ALIGN inline void push(const entry_t &e) + { + if (is_empty() || (e.time() <= (m_end - 1)->time())) + { + *m_end++ = e; + //inc_stat(m_prof_end); + } + else + { + entry_t * RESTRICT i = m_end++; + while ((i>&m_list[0]) && (e.time() > (i-1)->time()) ) + { + i--; + *(i+1) = *i; + //inc_stat(m_prof_sortmove); + } + *i = e; + //inc_stat(m_prof_sort); + } + assert(m_end - m_list < _Size); + } + + ATTR_HOT inline const entry_t pop() + { + return *--m_end; + } + + ATTR_HOT inline const entry_t peek() const + { + return *(m_end-1); + } + + ATTR_COLD void clear() + { + m_end = &m_list[0]; + } + // profiling + + INT32 m_prof_start; + INT32 m_prof_end; + INT32 m_prof_sortmove; + INT32 m_prof_sort; +private: + + entry_t * RESTRICT m_end; + //entry_t *m_list; + entry_t m_list[_Size]; + +}; + + +#endif /* NLLISTS_H_ */ diff --git a/src/emu/netlist/nl_parser.c b/src/emu/netlist/nl_parser.c new file mode 100644 index 00000000000..3116ef81061 --- /dev/null +++ b/src/emu/netlist/nl_parser.c @@ -0,0 +1,207 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * nl_parser.c + * + */ + +#include "nl_parser.h" + +// ---------------------------------------------------------------------------------------- +// A netlist parser +// ---------------------------------------------------------------------------------------- + +void netlist_parser::parse(char *buf) +{ + m_p = buf; + while (*m_p) + { + astring n; + skipws(); + if (!*m_p) break; + n = getname('('); + NL_VERBOSE_OUT(("Parser: Device: %s\n", n.cstr())); + if (n == "NET_ALIAS") + net_alias(); + else if (n == "NETDEV_PARAM") + netdev_param(); + else if ((n == "NETDEV_TTL_CONST") || (n == "NETDEV_ANALOG_CONST")) + netdev_const(n); + else + netdev_device(n); + } +} + +void netlist_parser::net_alias() +{ + astring alias; + astring out; + skipws(); + alias = getname(','); + skipws(); + out = getname(')'); + NL_VERBOSE_OUT(("Parser: Alias: %s %s\n", alias.cstr(), out.cstr())); + m_setup.register_alias(alias, out); +} + +void netlist_parser::netdev_param() +{ + astring param; + double val; + skipws(); + param = getname(','); + skipws(); + val = eval_param(); + NL_VERBOSE_OUT(("Parser: Param: %s %f\n", param.cstr(), val)); + m_setup.find_param(param).initial(val); + check_char(')'); +} + +void netlist_parser::netdev_const(const astring &dev_name) +{ + astring name; + net_device_t *dev; + astring paramfq; + double val; + + skipws(); + name = getname(','); + dev = net_create_device_by_name(dev_name, m_setup, name); + m_setup.register_dev(dev); + skipws(); + val = eval_param(); + check_char(')'); + paramfq = name; + paramfq.cat(".CONST"); + NL_VERBOSE_OUT(("Parser: Const: %s %f\n", name.cstr(), val)); + m_setup.find_param(paramfq).initial(val); +} + +void netlist_parser::netdev_device(const astring &dev_type) +{ + astring devname; + net_device_t *dev; + int cnt; + + skipws(); + devname = getname2(',', ')'); + dev = net_create_device_by_name(dev_type, m_setup, devname); + m_setup.register_dev(dev); + skipws(); + NL_VERBOSE_OUT(("Parser: IC: %s\n", devname.cstr())); + cnt = 0; + while (*m_p != ')') + { + m_p++; + skipws(); + astring output_name = getname2(',', ')'); + NL_VERBOSE_OUT(("Parser: ID: %s %s\n", output_name.cstr(), dev->m_inputs.item(cnt)->cstr())); + m_setup.register_link(*dev->m_inputs.item(cnt), output_name); + skipws(); + cnt++; + } + if (cnt != dev->m_inputs.count() && !dev->variable_input_count()) + fatalerror("netlist: input count mismatch for %s - expected %d found %d\n", devname.cstr(), dev->m_inputs.count(), cnt); + if (dev->variable_input_count()) + { + NL_VERBOSE_OUT(("variable inputs %s: %d\n", dev->name().cstr(), cnt)); + } + check_char(')'); +} + +// ---------------------------------------------------------------------------------------- +// private +// ---------------------------------------------------------------------------------------- + +void netlist_parser::skipeol() +{ + while (*m_p) + { + if (*m_p == 10) + { + m_p++; + if (*m_p && *m_p == 13) + m_p++; + return; + } + m_p++; + } +} + +void netlist_parser::skipws() +{ + while (*m_p) + { + switch (*m_p) + { + case ' ': + case 9: + case 10: + case 13: + m_p++; + break; + case '/': + if (*(m_p+1) == '/') + skipeol(); + break; + default: + return; + } + } +} + +astring netlist_parser::getname(char sep) +{ + char buf[300]; + char *p1 = buf; + + while (*m_p != sep) + *p1++ = *m_p++; + *p1 = 0; + m_p++; + return astring(buf); +} + +astring netlist_parser::getname2(char sep1, char sep2) +{ + char buf[300]; + char *p1 = buf; + + while ((*m_p != sep1) && (*m_p != sep2)) + *p1++ = *m_p++; + *p1 = 0; + return astring(buf); +} + +void netlist_parser::check_char(char ctocheck) +{ + skipws(); + if (*m_p == ctocheck) + { + m_p++; + return; + } + fatalerror("Parser: expected '%c' found '%c'\n", ctocheck, *m_p); +} + +double netlist_parser::eval_param() +{ + static const char *macs[6] = {"", "RES_K(", "RES_M(", "CAP_U(", "CAP_N(", "CAP_P("}; + static double facs[6] = {1, 1e3, 1e6, 1e-6, 1e-9, 1e-12}; + int i; + int f=0; + char *e; + double ret; + char *s = m_p; + + for (i=1; i<6;i++) + if (strncmp(s, macs[i], strlen(macs[i])) == 0) + f = i; + ret = strtod(s+strlen(macs[f]), &e); + if ((f>0) && (*e != ')')) + fatalerror("Parser: Error with parameter ...\n"); + if (f>0) + e++; + m_p = e; + return ret * facs[f]; +} diff --git a/src/emu/netlist/nl_parser.h b/src/emu/netlist/nl_parser.h new file mode 100644 index 00000000000..79b3882ac37 --- /dev/null +++ b/src/emu/netlist/nl_parser.h @@ -0,0 +1,39 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * nl_parser.c + * + */ + +#ifndef NL_PARSER_H_ +#define NL_PARSER_H_ + +#include "nl_setup.h" + +class netlist_parser +{ +public: + netlist_parser(netlist_setup_t &setup) + : m_setup(setup) {} + + void parse(char *buf); + void net_alias(); + void netdev_param(); + void netdev_const(const astring &dev_name); + void netdev_device(const astring &dev_type); + +private: + + void skipeol(); + void skipws(); + astring getname(char sep); + astring getname2(char sep1, char sep2); + void check_char(char ctocheck); + double eval_param(); + + char * m_p; + netlist_setup_t &m_setup; +}; + + +#endif /* NL_PARSER_H_ */ diff --git a/src/emu/netlist/nl_setup.c b/src/emu/netlist/nl_setup.c new file mode 100644 index 00000000000..3cf1795c488 --- /dev/null +++ b/src/emu/netlist/nl_setup.c @@ -0,0 +1,318 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * nlsetup.c + * + */ + +#include "nl_base.h" +#include "nl_setup.h" +#include "nl_parser.h" +#include "devices/nld_system.h" + +static NETLIST_START(base) + NETDEV_TTL_CONST(ttlhigh, 1) + NETDEV_TTL_CONST(ttllow, 0) + NETDEV_ANALOG_CONST(NC, NETLIST_HIGHIMP_V) +NETLIST_END + + +// ---------------------------------------------------------------------------------------- +// netlist_setup_t +// ---------------------------------------------------------------------------------------- + +netlist_setup_t::netlist_setup_t(netlist_base_t &netlist) + : m_netlist(netlist) +{ + NETLIST_NAME(base)(*this); +} + +template <class T> +static void tagmap_free_entries(T &tm) +{ + for (typename T::entry_t *entry = tm.first(); entry != NULL; entry = tm.next(entry)) + { + delete entry->object(); + } + tm.reset(); +} + +netlist_setup_t::~netlist_setup_t() +{ + tagmap_free_entries<tagmap_devices_t>(m_devices); + tagmap_free_entries<tagmap_astring_t>(m_links); + tagmap_free_entries<tagmap_astring_t>(m_alias); + m_params.reset(); + m_terminals.reset(); +} + +net_device_t *netlist_setup_t::register_dev(net_device_t *dev) +{ + if (!(m_devices.add(dev->name(), dev, false)==TMERR_NONE)) + fatalerror("Error adding %s to device list\n", dev->name().cstr()); + return dev; +} + +template <class T> +static void remove_start_with(T &hm, astring &sw) +{ + typename T::entry_t *entry = hm.first(); + while (entry != NULL) + { + typename T::entry_t *next = hm.next(entry); + if (sw.cmpsubstr(entry->tag(), 0, sw.len()) == 0) + { + NL_VERBOSE_OUT(("removing %s\n", entry->tag().cstr())); + hm.remove(entry->object()); + } + entry = next; + } +} + +void netlist_setup_t::remove_dev(const astring &name) +{ + net_device_t *dev = m_devices.find(name); + astring temp = name; + if (dev == NULL) + fatalerror("Device %s does not exist\n", name.cstr()); + + temp.cat("."); + + //remove_start_with<tagmap_input_t>(m_inputs, temp); + remove_start_with<tagmap_terminal_t>(m_terminals, temp); + remove_start_with<tagmap_param_t>(m_params, temp); + remove_start_with<tagmap_astring_t>(m_links, temp); + m_devices.remove(name); +} + +void netlist_setup_t::register_callback(const astring &devname, netlist_output_delegate delegate) +{ + NETLIB_NAME(netdev_analog_callback) *dev = (NETLIB_NAME(netdev_analog_callback) *) m_devices.find(devname); + if (dev == NULL) + fatalerror("did not find device %s\n", devname.cstr()); + dev->register_callback(delegate); +} + +void netlist_setup_t::register_alias(const astring &alias, const astring &out) +{ + if (!(m_alias.add(alias, new astring(out), false)==TMERR_NONE)) + fatalerror("Error adding alias %s to alias list\n", alias.cstr()); +} + +void netlist_setup_t::register_output(netlist_core_device_t &dev, netlist_core_device_t &upd_dev, const astring &name, net_output_t &out) +{ + NL_VERBOSE_OUT(("out %s\n", name.cstr())); + astring temp = dev.name(); + temp.cat("."); + temp.cat(name); + out.init_terminal(&upd_dev); + if (!(m_terminals.add(temp, &out, false)==TMERR_NONE)) + fatalerror("Error adding output %s to output list\n", name.cstr()); +} + +void netlist_setup_t::register_input(net_device_t &dev, netlist_core_device_t &upd_dev, const astring &name, net_input_t &inp, net_input_t::net_input_state type) +{ + NL_VERBOSE_OUT(("input %s\n", name.cstr())); + astring temp = dev.name(); + temp.cat("."); + temp.cat(name); + inp.init_input(&upd_dev, type); + dev.m_inputs.add(temp); + if (!(m_terminals.add(temp, &inp, false) == TMERR_NONE)) + fatalerror("Error adding input %s to input list\n", name.cstr()); +} + +void netlist_setup_t::register_link(const astring &sin, const astring &sout) +{ + const astring *temp = new astring(sout); + NL_VERBOSE_OUT(("link %s <== %s\n", sin.cstr(), sout.cstr())); + if (!(m_links.add(sin, temp, false)==TMERR_NONE)) + fatalerror("Error adding link %s<==%s to link list\n", sin.cstr(), sout.cstr()); +} + + +void netlist_setup_t::register_param(const astring &name, net_param_t *param) +{ + astring temp = param->netdev().name(); + temp.cat("."); + temp.cat(name); + if (!(m_params.add(temp, param, false)==TMERR_NONE)) + fatalerror("Error adding parameter %s to parameter list\n", name.cstr()); +} + + +const astring &netlist_setup_t::resolve_alias(const astring &name) const +{ + const astring *ret = m_alias.find(name); + if (ret != NULL) + return *ret; + return name; +} + +net_output_t *netlist_setup_t::find_output_exact(const astring &outname_in) +{ + net_terminal_t *term = m_terminals.find(outname_in); + return dynamic_cast<net_output_t *>(term); +} + +net_output_t &netlist_setup_t::find_output(const astring &outname_in) +{ + const astring &outname = resolve_alias(outname_in); + net_output_t *ret; + + ret = find_output_exact(outname); + /* look for default */ + if (ret == NULL) + { + /* look for ".Q" std output */ + astring s = outname; + s.cat(".Q"); + ret = find_output_exact(s); + } + if (ret == NULL) + fatalerror("output %s(%s) not found!\n", outname_in.cstr(), outname.cstr()); + NL_VERBOSE_OUT(("Found input %s\n", outname.cstr())); + return *ret; +} + +net_param_t &netlist_setup_t::find_param(const astring ¶m_in) +{ + const astring &outname = resolve_alias(param_in); + net_param_t *ret; + + ret = m_params.find(outname); + if (ret == NULL) + fatalerror("parameter %s(%s) not found!\n", param_in.cstr(), outname.cstr()); + NL_VERBOSE_OUT(("Found parameter %s\n", outname.cstr())); + return *ret; +} + +void netlist_setup_t::resolve_inputs(void) +{ + NL_VERBOSE_OUT(("Resolving ...\n")); + int proxy_cnt = 0; + for (tagmap_astring_t::entry_t *entry = m_links.first(); entry != NULL; entry = m_links.next(entry)) + { + const astring *sout = entry->object(); + astring sin = entry->tag(); + net_input_t *in = dynamic_cast<net_input_t *>(m_terminals.find(sin)); + + if (in == NULL) + fatalerror("Unable to find %s\n", sin.cstr()); + + net_output_t &out = find_output(sout->cstr()); + if (out.object_type(net_output_t::SIGNAL_MASK) == net_output_t::SIGNAL_ANALOG + && in->object_type(net_output_t::SIGNAL_MASK) == net_output_t::SIGNAL_DIGITAL) + { + netdev_a_to_d_proxy *proxy = new netdev_a_to_d_proxy(*in); + astring x = ""; + x.printf("proxy_ad_%d", proxy_cnt++); + + proxy->init(*this, x.cstr()); + register_dev(proxy); + + in->set_output(proxy->m_Q); + proxy->m_Q.register_con(*in); + proxy->m_I.set_output(out); + out.register_con(proxy->m_I); + + } + else if (out.object_type(net_output_t::SIGNAL_MASK) == net_output_t::SIGNAL_DIGITAL + && in->object_type(net_output_t::SIGNAL_MASK) == net_output_t::SIGNAL_ANALOG) + { + //printf("here 1\n"); + netdev_d_to_a_proxy *proxy = new netdev_d_to_a_proxy(out); + astring x = ""; + x.printf("proxy_da_%d", proxy_cnt++); + proxy->init(*this, x.cstr()); + register_dev(proxy); + + in->set_output(proxy->m_Q); + proxy->m_Q.register_con(*in); + proxy->m_I.set_output(out); + out.register_con(proxy->m_I); + //printf("here 2\n"); + } + else + { + in->set_output(out); + out.register_con(*in); + } + } + + /* find the main clock ... */ + for (tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry)) + { + net_device_t *dev = entry->object(); + if (dynamic_cast<NETLIB_NAME(netdev_mainclock)*>(dev) != NULL) + { + m_netlist.set_mainclock_dev(dynamic_cast<NETLIB_NAME(netdev_mainclock)*>(dev)); + } + } + +#if 1 + +#else + /* make sure all outputs are triggered once */ + for (tagmap_output_t::entry_t *entry = m_outputs.first(); entry != NULL; entry = m_outputs.next(entry)) + { + net_output_t *out = entry->object(); + //if (dynamic_cast<const netdev_clock *>(out->netdev()) == NULL ) + { + out->update_devs_force(); + INT32 time = 10000; + m_netlist.process_list(time); + } + } + //m_netlist.m_queue.clear(); +#endif + + /* print all outputs */ + for (tagmap_terminal_t::entry_t *entry = m_terminals.first(); entry != NULL; entry = m_terminals.next(entry)) + { + ATTR_UNUSED net_output_t *out = dynamic_cast<net_output_t *>(entry->object()); + //if (out != NULL) + //VERBOSE_OUT(("%s %d\n", out->netdev()->name(), *out->Q_ptr())); + } + + +} + +void netlist_setup_t::step_devices_once(void) +{ + /* make sure params are set now .. */ + for (tagmap_param_t::entry_t *entry = m_params.first(); entry != NULL; entry = m_params.next(entry)) + { + entry->object()->netdev().update_param(); + } + + for (tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry)) + { + net_device_t *dev = entry->object(); + dev->update_dev(); + } +} + + +void netlist_setup_t::parse(char *buf) +{ + netlist_parser parser(*this); + parser.parse(buf); +} + +void netlist_setup_t::print_stats() +{ + if (NL_KEEP_STATISTICS) + { + for (netlist_setup_t::tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry)) + { + //entry->object()->s + printf("Device %20s : %12d %15ld\n", entry->object()->name().cstr(), entry->object()->stat_count, (long int) entry->object()->total_time / (entry->object()->stat_count + 1)); + } + printf("Queue Start %15d\n", m_netlist.m_queue.m_prof_start); + printf("Queue End %15d\n", m_netlist.m_queue.m_prof_end); + printf("Queue Sort %15d\n", m_netlist.m_queue.m_prof_sort); + printf("Queue Move %15d\n", m_netlist.m_queue.m_prof_sortmove); + } +} + diff --git a/src/emu/netlist/nl_setup.h b/src/emu/netlist/nl_setup.h new file mode 100644 index 00000000000..ffc07c9b17d --- /dev/null +++ b/src/emu/netlist/nl_setup.h @@ -0,0 +1,113 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * nlsetup.h + * + * Created on: 3 Nov 2013 + * Author: andre + */ + +#ifndef NLSETUP_H_ +#define NLSETUP_H_ + +#include "nl_base.h" + +//============================================================ +// MACROS / inline netlist definitions +//============================================================ + +#define NET_ALIAS(_alias, _name) \ + netlist.register_alias(# _alias, # _name); +#define NET_NEW(_type , _name) net_create_device_by_classname(NETLIB_NAME_STR(_type), netlist, # _name) + +#define NET_REGISTER_DEV(_type, _name) \ + netlist.register_dev(NET_NEW(_type, _name)); +#define NET_REMOVE_DEV(_name) \ + netlist.remove_dev(# _name); +#define NET_REGISTER_SIGNAL(_type, _name) \ + NET_REGISTER_DEV(_type ## _ ## sig, _name) +#define NET_CONNECT(_name, _input, _output) \ + netlist.register_link(# _name "." # _input, # _output); +#define NETDEV_PARAM(_name, _val) \ + netlist.find_param(# _name).initial(_val); + +#define NETLIST_NAME(_name) netlist ## _ ## _name + +#define NETLIST_START(_name) \ +ATTR_COLD void NETLIST_NAME(_name)(netlist_setup_t &netlist) \ +{ + +#define NETLIST_END } + +#define NETLIST_INCLUDE(_name) \ + NETLIST_NAME(_name)(netlist); + +#define NETLIST_MEMREGION(_name) \ + netlist.parse((char *)downcast<netlist_t &>(netlist.netlist()).machine().root_device().memregion(_name)->base()); + +// ---------------------------------------------------------------------------------------- +// FIXME: Clean this up +// ---------------------------------------------------------------------------------------- + +class NETLIB_NAME(netdev_analog_callback); + +// ---------------------------------------------------------------------------------------- +// netlist_setup_t +// ---------------------------------------------------------------------------------------- + +class netlist_setup_t +{ +public: + + typedef tagmap_t<net_device_t *, 393> tagmap_devices_t; + typedef tagmap_t<const astring *, 393> tagmap_astring_t; + typedef tagmap_t<net_param_t *, 393> tagmap_param_t; + typedef tagmap_t<net_terminal_t *, 393> tagmap_terminal_t; + + netlist_setup_t(netlist_base_t &netlist); + ~netlist_setup_t(); + + netlist_base_t &netlist() { return m_netlist; } + + net_device_t *register_dev(net_device_t *dev); + void remove_dev(const astring &name); + + void register_output(netlist_core_device_t &dev, netlist_core_device_t &upd_dev, const astring &name, net_output_t &out); + void register_input(net_device_t &dev, netlist_core_device_t &upd_dev, const astring &name, net_input_t &inp, net_input_t::net_input_state type); + void register_alias(const astring &alias, const astring &out); + void register_param(const astring &sname, net_param_t *param); + + void register_link(const astring &sin, const astring &sout); + + net_output_t &find_output(const astring &outname_in); + net_param_t &find_param(const astring ¶m_in); + + void register_callback(const astring &devname, netlist_output_delegate delegate); + + void parse(char *buf); + + void resolve_inputs(void); + void step_devices_once(void); + + /* not ideal, but needed for save_state */ + tagmap_terminal_t m_terminals; + + void print_stats(); + +protected: + +private: + + netlist_base_t &m_netlist; + + tagmap_devices_t m_devices; + tagmap_astring_t m_alias; + //tagmap_input_t m_inputs; + tagmap_param_t m_params; + tagmap_astring_t m_links; + + net_output_t *find_output_exact(const astring &outname_in); + const astring &resolve_alias(const astring &name) const; +}; + +#endif /* NLSETUP_H_ */ diff --git a/src/emu/netlist/nl_time.h b/src/emu/netlist/nl_time.h new file mode 100644 index 00000000000..740e10d8572 --- /dev/null +++ b/src/emu/netlist/nl_time.h @@ -0,0 +1,99 @@ +// license:GPL-2.0+ +// copyright-holders:Couriersud +/* + * nltime.h + */ + +#ifndef NLTIME_H_ +#define NLTIME_H_ + +#include "nl_config.h" + +//============================================================ +// MACROS +//============================================================ + +#define NLTIME_FROM_NS(_t) netlist_time::from_nsec(_t) +#define NLTIME_FROM_US(_t) netlist_time::from_usec(_t) +#define NLTIME_FROM_MS(_t) netlist_time::from_msec(_t) +#define NLTIME_IMMEDIATE netlist_time::from_nsec(0) + +// ---------------------------------------------------------------------------------------- +// net_list_time +// ---------------------------------------------------------------------------------------- + +struct netlist_time +{ +public: + + typedef UINT64 INTERNALTYPE; + + static const INTERNALTYPE RESOLUTION = NETLIST_INTERNAL_RES; + + ATTR_HOT inline netlist_time() : m_time(0) {} + + ATTR_HOT friend inline const netlist_time operator-(const netlist_time &left, const netlist_time &right); + ATTR_HOT friend inline const netlist_time operator+(const netlist_time &left, const netlist_time &right); + ATTR_HOT friend inline const netlist_time operator*(const netlist_time &left, const UINT32 factor); + ATTR_HOT friend inline bool operator>(const netlist_time &left, const netlist_time &right); + ATTR_HOT friend inline bool operator<(const netlist_time &left, const netlist_time &right); + ATTR_HOT friend inline bool operator>=(const netlist_time &left, const netlist_time &right); + ATTR_HOT friend inline bool operator<=(const netlist_time &left, const netlist_time &right); + + ATTR_HOT inline const netlist_time &operator=(const netlist_time &right) { m_time = right.m_time; return *this; } + ATTR_HOT inline const netlist_time &operator+=(const netlist_time &right) { m_time += right.m_time; return *this; } + + ATTR_HOT inline const INTERNALTYPE as_raw() const { return m_time; } + + ATTR_HOT static inline const netlist_time from_nsec(const int ns) { return netlist_time((UINT64) ns * (RESOLUTION / U64(1000000000))); } + ATTR_HOT static inline const netlist_time from_usec(const int us) { return netlist_time((UINT64) us * (RESOLUTION / U64(1000000))); } + ATTR_HOT static inline const netlist_time from_msec(const int ms) { return netlist_time((UINT64) ms * (RESOLUTION / U64(1000))); } + ATTR_HOT static inline const netlist_time from_hz(const UINT64 hz) { return netlist_time(RESOLUTION / hz); } + ATTR_HOT static inline const netlist_time from_raw(const INTERNALTYPE raw) { return netlist_time(raw); } + + static const netlist_time zero; + +protected: + + ATTR_HOT inline netlist_time(const INTERNALTYPE val) : m_time(val) {} + + INTERNALTYPE m_time; +}; + +ATTR_HOT inline const netlist_time operator-(const netlist_time &left, const netlist_time &right) +{ + return netlist_time::from_raw(left.m_time - right.m_time); +} + +ATTR_HOT inline const netlist_time operator*(const netlist_time &left, const UINT32 factor) +{ + return netlist_time::from_raw(left.m_time * factor); +} + +ATTR_HOT inline const netlist_time operator+(const netlist_time &left, const netlist_time &right) +{ + return netlist_time::from_raw(left.m_time + right.m_time); +} + +ATTR_HOT inline bool operator<(const netlist_time &left, const netlist_time &right) +{ + return (left.m_time < right.m_time); +} + +ATTR_HOT inline bool operator>(const netlist_time &left, const netlist_time &right) +{ + return (left.m_time > right.m_time); +} + +ATTR_HOT inline bool operator<=(const netlist_time &left, const netlist_time &right) +{ + return (left.m_time <= right.m_time); +} + +ATTR_HOT inline bool operator>=(const netlist_time &left, const netlist_time &right) +{ + return (left.m_time >= right.m_time); +} + + +#endif /* NLTIME_H_ */ diff --git a/src/mame/drivers/pong.c b/src/mame/drivers/pong.c index 9ec2c4b8e08..49c475da5e3 100644 --- a/src/mame/drivers/pong.c +++ b/src/mame/drivers/pong.c @@ -18,7 +18,7 @@ TODO: #include "machine/rescap.h" #include "machine/netlist.h" -#include "netlist/net_lib.h" +#include "netlist/devices/net_lib.h" #include "sound/dac.h" #include "video/fixfreq.h" #include "astring.h" @@ -562,8 +562,8 @@ void pong_state::machine_reset() void pong_state::video_start() { - m_maincpu->setup().register_callback("sound_cb", net_output_delegate(&pong_state::sound_cb, "pong_state::sound_cb", this)); - m_maincpu->setup().register_callback("video_cb", net_output_delegate(&pong_state::video_cb, "pong_state::video_cb", this)); + m_maincpu->setup().register_callback("sound_cb", netlist_output_delegate(&pong_state::sound_cb, "pong_state::sound_cb", this)); + m_maincpu->setup().register_callback("video_cb", netlist_output_delegate(&pong_state::video_cb, "pong_state::video_cb", this)); } |