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.

This commit is contained in:
Couriersud 2013-11-04 20:47:32 +00:00
parent 39dc549a5f
commit bf19099323
21 changed files with 2800 additions and 2491 deletions

17
.gitattributes vendored
View File

@ -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

View File

@ -60,6 +60,7 @@ OBJDIRS += \
$(EMUOBJ)/drivers \
$(EMUOBJ)/machine \
$(EMUOBJ)/netlist \
$(EMUOBJ)/netlist/devices \
$(EMUOBJ)/layout \
$(EMUOBJ)/imagedev \
$(EMUOBJ)/video \

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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
}

View File

@ -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;

View File

@ -0,0 +1,6 @@
/*
* nld_7400.c
*
*/

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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 \

435
src/emu/netlist/nl_base.c Normal file
View File

@ -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 &param, double initialVal)
{
param.set_netdev(dev);
param.initial(initialVal);
m_setup->register_param(name, &param);
}
void net_device_t::register_param(const astring &name, net_param_t &param, 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);
}

811
src/emu/netlist/nl_base.h Normal file
View File

@ -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 &param, const double initialVal = 0.0);
ATTR_COLD void register_param(netlist_core_device_t &dev, const astring &sname, net_param_t &param, 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_ */

103
src/emu/netlist/nl_config.h Normal file
View File

@ -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_ */

134
src/emu/netlist/nl_lists.h Normal file
View File

@ -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_ */

207
src/emu/netlist/nl_parser.c Normal file
View File

@ -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];
}

View File

@ -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_ */

318
src/emu/netlist/nl_setup.c Normal file
View File

@ -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 &param_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);
}
}

113
src/emu/netlist/nl_setup.h Normal file
View File

@ -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 &param_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_ */

99
src/emu/netlist/nl_time.h Normal file
View File

@ -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_ */

View File

@ -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));
}