diff --git a/.gitattributes b/.gitattributes index bef9e2d478c..faf2a71d5ef 100644 --- a/.gitattributes +++ b/.gitattributes @@ -946,6 +946,10 @@ src/emu/machine/msm6242.c svneol=native#text/plain src/emu/machine/msm6242.h svneol=native#text/plain src/emu/machine/ncr539x.c svneol=native#text/plain src/emu/machine/ncr539x.h svneol=native#text/plain +src/emu/machine/net_lib.c svneol=native#text/plain +src/emu/machine/net_lib.h svneol=native#text/plain +src/emu/machine/netlist.c svneol=native#text/plain +src/emu/machine/netlist.h svneol=native#text/plain src/emu/machine/nmc9306.c svneol=native#text/plain src/emu/machine/nmc9306.h svneol=native#text/plain src/emu/machine/nscsi_bus.c svneol=native#text/plain diff --git a/src/emu/emu.mak b/src/emu/emu.mak index 3a00258ec72..5caf39ccc5a 100644 --- a/src/emu/emu.mak +++ b/src/emu/emu.mak @@ -220,6 +220,8 @@ EMUMACHINEOBJS = \ $(EMUMACHINE)/msm58321.o \ $(EMUMACHINE)/msm6242.o \ $(EMUMACHINE)/ncr539x.o \ + $(EMUMACHINE)/netlist.o \ + $(EMUMACHINE)/net_lib.o \ $(EMUMACHINE)/nmc9306.o \ $(EMUMACHINE)/nscsi_bus.o \ $(EMUMACHINE)/nscsi_cd.o \ diff --git a/src/emu/machine/net_lib.c b/src/emu/machine/net_lib.c new file mode 100644 index 00000000000..1852407adf9 --- /dev/null +++ b/src/emu/machine/net_lib.c @@ -0,0 +1,757 @@ +/*************************************************************************** + + netlib.c + + Discrete netlist implementation. + +**************************************************************************** + + Couriersud reserves the right to license the code under a less restrictive + license going forward. + + Copyright Nicola Salmoria and the MAME team + All rights reserved. + + Redistribution and use of this code or any derivative works are permitted + provided that the following conditions are met: + + * Redistributions may not be sold, nor may they be used in a commercial + product or activity. + + * Redistributions that are modified from the original source must include the + complete source code, including the source code for all components used by a + binary built from the modified sources. However, as a special exception, the + source code distributed need not include anything that is normally distributed + (in either source or binary form) with the major components (compiler, kernel, + and so on) of the operating system on which the executable runs, unless that + component itself accompanies the executable. + + * Redistributions must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + +****************************************************************************/ + +#include "net_lib.h" + + +NETLIB_START(netdev_const) +{ + register_output("Q", &m_Q); + register_param("CONST", &m_const, 0.0); +} + +NETLIB_UPDATE(netdev_const) +{ +} + +NETLIB_UPDATE_PARAM(netdev_const) +{ + m_Q.setTo(m_const.ValueInt()); +} + +NETLIB_START(netdev_input) +{ + register_output("Q", &m_Q); +} + +NETLIB_UPDATE(netdev_input) +{ +} + +NETLIB_START(netdev_delay_lh) +{ + register_input("CLK", &m_clk); + register_input("D", &m_D, NET_INP_TYPE_PASSIVE); + register_output("Q", &m_Q); + + m_lastclk = nst_LOW; + m_Q.initial(1); +} + +NETLIB_UPDATE(netdev_delay_lh) +{ + UINT8 oclk = m_lastclk; + m_lastclk = INPVAL(m_clk); + if (!oclk && m_lastclk) + m_Q.setTo(INPVAL(m_D)); +} + +NETLIB_START(nicMultiSwitch) +{ + static const char *sIN[8] = { "i1", "i2", "i3", "i4", "i5", "i6", "i7", "i8" }; + int i; + + m_position = 0; + m_low.initial(0); + + for (i=0; i<8; i++) + { + register_input(sIN[i], &m_I[i]); + m_I[i].o = GETINPPTR(m_low); + } + register_param("POS", &m_POS); + register_output("Q", &m_Q); + + m_variable_input_count = true; +} + +NETLIB_UPDATE(nicMultiSwitch) +{ + m_Q.setTo(INPVAL(m_I[m_position])); +} + +NETLIB_UPDATE_PARAM(nicMultiSwitch) +{ + m_position = m_POS.ValueInt(); + update(); +} + +NETLIB_START(nicRSFF) +{ + register_input("S", &m_S); + register_input("R", &m_R); + register_output("Q", &m_Q); + register_output("QQ", &m_QQ); +} + +NETLIB_UPDATE(nicRSFF) +{ + if (INPVAL(m_S)) + { + m_Q.set(); + m_QQ.clear(); + } + else if (INPVAL(m_R)) + { + m_Q.clear(); + m_QQ.set(); + } +} + + +NETLIB_START(nicNE555N_MSTABLE) +{ + register_input("TRIG", &m_trigger); + register_output("Q", &m_Q); + register_param("R", &m_R); + register_param("C", &m_C); + register_param("VS", &m_VS, 5.0); + register_param("VL", &m_VL, 0.0 *5.0); + register_param("VT", &m_VT, 0.67*5.0); + + m_Q.initial(0); + + m_timer = m_setup->netlist().alloc_timer(this, 0); +} + +NETLIB_UPDATE_PARAM(nicNE555N_MSTABLE) +{ + double vt = m_VT.Value(); + double vl = m_VL.Value(); + + if (vt > m_VS.Value()-0.7) + vt = m_VS.Value()-0.7; + + if (vt < 1.4) + vt = 1.4; + + if (vtadjust_timer(m_time); + m_Q.set(); + } + } + else if (m_fired) + { + if (INPVAL(m_trigger)) + m_Q.clear(); + } + m_last = INPVAL(m_trigger); +} + +NETLIB_TIMER_CALLBACK(nicNE555N_MSTABLE) +{ + if (INPVAL(m_trigger)) + m_Q.clear(); + m_fired = 1; +} + + +NETLIB_UPDATE(nic7400) +{ + UINT8 t = (INPVAL(m_i[0]) & INPVAL(m_i[1])) ^ 1; + m_Q.setTo(t, t ? 22 : 15); +} + +NETLIB_UPDATE(nic7402) +{ + UINT8 t = (INPVAL(m_i[0]) | INPVAL(m_i[1])) ^ 1; + m_Q.setTo(t, t ? 22 : 15); +} + +NETLIB_UPDATE(nic7404) +{ + UINT8 t = (INPVAL(m_i[0])) ^ 1; + m_Q.setTo(t, t ? 22 : 15); +} + +NETLIB_UPDATE(nic7410) +{ + UINT8 t = (INPVAL(m_i[0]) & INPVAL(m_i[1]) & INPVAL(m_i[2])) ^ 1; + m_Q.setTo(t, t ? 22 : 15); +} + +NETLIB_UPDATE(nic7420) +{ + UINT8 t = (INPVAL(m_i[0]) & INPVAL(m_i[1]) & INPVAL(m_i[2]) & INPVAL(m_i[3])) ^ 1; + m_Q.setTo(t, t ? 22 : 15); +} + +NETLIB_UPDATE(nic7425) +{ + UINT8 t = (INPVAL(m_i[0]) | INPVAL(m_i[1]) | INPVAL(m_i[2]) | INPVAL(m_i[3])) ^ 1; + m_Q.setTo(t, t ? 22 : 15); +} + +NETLIB_UPDATE(nic7427) +{ + UINT8 t = (INPVAL(m_i[0]) | INPVAL(m_i[1]) | INPVAL(m_i[2])) ^ 1; + m_Q.setTo(t, t ? 22 : 15); +} + +NETLIB_UPDATE(nic7430) +{ + UINT8 t = (INPVAL(m_i[0]) & INPVAL(m_i[1]) & INPVAL(m_i[2]) & INPVAL(m_i[3]) & INPVAL(m_i[4]) & INPVAL(m_i[5]) & INPVAL(m_i[6]) & INPVAL(m_i[7])) ^ 1; + m_Q.setTo(t, t ? 22 : 15); +} + +NETLIB_UPDATE(nic7486) +{ + UINT8 t = INPVAL(m_i[0]) ^ INPVAL(m_i[1]); + m_Q.setTo(t, t ? 22 : 15 ); +} + +NETLIB_START(nic7448) +{ + register_input("A0", &m_A0); + register_input("A1", &m_A1); + register_input("A2", &m_A2); + register_input("A3", &m_A3); + register_input("LTQ", &m_LTQ); + register_input("BIQ", &m_BIQ); + register_input("RBIQ",&m_RBIQ); + + register_output("a", &m_a); + register_output("b", &m_b); + register_output("c", &m_c); + register_output("d", &m_d); + register_output("e", &m_e); + register_output("f", &m_f); + register_output("g", &m_g); +} + +NETLIB_UPDATE(nic7448) +{ + UINT8 v; + + if (INPVAL(m_BIQ) && !INPVAL(m_LTQ)) + v = 8; + else + { + v = (INPVAL(m_A0) << 0) | (INPVAL(m_A1) << 1) | (INPVAL(m_A2) << 2) | (INPVAL(m_A3) << 3); + if (!INPVAL(m_BIQ) || (!INPVAL(m_RBIQ) && (v==0))) + v = 15; + } + + if (v != m_state) + { + m_a.setTo(tab7448[v][0]); + m_b.setTo(tab7448[v][1]); + m_c.setTo(tab7448[v][2]); + m_d.setTo(tab7448[v][3]); + m_e.setTo(tab7448[v][4]); + m_f.setTo(tab7448[v][5]); + m_g.setTo(tab7448[v][6]); + m_state = v; + } +} + +const UINT8 nic7448::tab7448[16][7] = +{ + { 1, 1, 1, 1, 1, 1, 0 }, /* 00 - not blanked ! */ + { 0, 1, 1, 0, 0, 0, 0 }, /* 01 */ + { 1, 1, 0, 1, 1, 0, 1 }, /* 02 */ + { 1, 1, 1, 1, 0, 0, 1 }, /* 03 */ + { 0, 1, 1, 0, 0, 1, 1 }, /* 04 */ + { 1, 0, 1, 1, 0, 1, 1 }, /* 05 */ + { 0, 0, 1, 1, 1, 1, 1 }, /* 06 */ + { 1, 1, 1, 0, 0, 0, 0 }, /* 07 */ + { 1, 1, 1, 1, 1, 1, 1 }, /* 08 */ + { 1, 1, 1, 0, 0, 1, 1 }, /* 09 */ + { 0, 0, 0, 1, 1, 0, 1 }, /* 10 */ + { 0, 0, 1, 1, 0, 0, 1 }, /* 11 */ + { 0, 1, 0, 0, 0, 1, 1 }, /* 12 */ + { 1, 0, 0, 1, 0, 1, 1 }, /* 13 */ + { 0, 0, 0, 1, 1, 1, 1 }, /* 14 */ + { 0, 0, 0, 0, 0, 0, 0 }, /* 15 */ +}; + +NETLIB_UPDATE(nic7450) +{ + UINT8 t1 = INPVAL(m_i[0]) & INPVAL(m_i[1]); + UINT8 t2 = INPVAL(m_i[2]) & INPVAL(m_i[3]); + UINT8 t = (t1 | t2) ^ 1; + m_Q.setTo(t, t ? 22 : 15); +} + +INLINE void nic7474_newstate(UINT8 state, net_output_t &Q, net_output_t &QQ) +{ + if (state != Q.Q()) + { + Q.setToNoCheck(state, state ? 40 : 25); + QQ.setToNoCheck(!state, !state ? 40 : 25); + } +} + +NETLIB_UPDATE(nic7474) +{ + net_sig_t old_clk = m_lastclk; + m_lastclk = INPVAL(m_clk); + + if (UNEXPECTED(!INPVAL(m_preQ))) + nic7474_newstate(1, m_Q, m_QQ); + else if (UNEXPECTED(!INPVAL(m_clrQ))) + nic7474_newstate(0, m_Q, m_QQ); + else if (!old_clk && m_lastclk) + nic7474_newstate(INPVAL(m_D), m_Q, m_QQ); +} + +NETLIB_START(nic7474) +{ + m_lastclk = 0; + + register_input("CLK", &m_clk); + register_input("D", &m_D, NET_INP_TYPE_PASSIVE); + register_input("CLRQ", &m_clrQ); + register_input("PREQ", &m_preQ); + + register_output("Q", &m_Q); + register_output("QQ", &m_QQ); + + m_Q.initial(0); + m_QQ.initial(1); +} + +NETLIB_START(nic7483) +{ + m_lastr = 0; + + register_input("A1", &m_A1); + register_input("A2", &m_A2); + register_input("A3", &m_A3); + register_input("A4", &m_A4); + register_input("B1", &m_B1); + register_input("B2", &m_B2); + register_input("B3", &m_B3); + register_input("B4", &m_B4); + register_input("CI", &m_CI); + + register_output("SA", &m_SA); + register_output("SB", &m_SB); + register_output("SC", &m_SC); + register_output("SD", &m_SD); + register_output("CO", &m_CO); +} + +NETLIB_UPDATE(nic7483) +{ + UINT8 a = (INPVAL(m_A1) << 0) | (INPVAL(m_A2) << 1) | (INPVAL(m_A3) << 2) | (INPVAL(m_A4) << 3); + UINT8 b = (INPVAL(m_B1) << 0) | (INPVAL(m_B2) << 1) | (INPVAL(m_B3) << 2) | (INPVAL(m_B4) << 3); + + UINT8 r = a + b + INPVAL(m_CI); + + if (r != m_lastr) + { + m_lastr = r; + m_SA.setTo((r >> 0) & 1); + m_SB.setTo((r >> 1) & 1); + m_SC.setTo((r >> 2) & 1); + m_SD.setTo((r >> 3) & 1); + m_CO.setTo((r >> 4) & 1); + } +} + +NETLIB_START(nic7490) +{ + m_lastclk = 0; + m_cnt = 0; + + register_input("CLK", &m_clk); + register_input("R1", &m_R1); + register_input("R2", &m_R2); + register_input("R91", &m_R91); + register_input("R92", &m_R92); + + register_output("QA", &m_QA); + register_output("QB", &m_QB); + register_output("QC", &m_QC); + register_output("QD", &m_QD); +} + +NETLIB_UPDATE(nic7490) +{ + UINT8 old_clk = m_lastclk; + m_lastclk = INPVAL(m_clk); + + if (UNEXPECTED(INPVAL(m_R91) & INPVAL(m_R92))) + { + m_cnt = 9; + update_outputs(); + } + else if (UNEXPECTED(INPVAL(m_R1) & INPVAL(m_R2))) + { + m_cnt = 0; + update_outputs(); + } + else if (old_clk & !m_lastclk) + { + m_cnt++; + if (m_cnt >= 10) + m_cnt = 0; + update_outputs(); + } +} + +NETLIB_FUNC_VOID(nic7490, update_outputs) +{ + m_QA.setTo((m_cnt >> 0) & 1); + m_QB.setTo((m_cnt >> 1) & 1); + m_QC.setTo((m_cnt >> 2) & 1); + m_QD.setTo((m_cnt >> 3) & 1); +} + +NETLIB_START(nic7493) +{ + m_lastclk = 0; + m_cnt = 0; + + register_input("CLK", &m_clk); + register_input("R1", &m_R1); + register_input("R2", &m_R2); + + register_output("QA", &m_QA); + register_output("QB", &m_QB); + register_output("QC", &m_QC); + register_output("QD", &m_QD); +} + +NETLIB_UPDATE(nic7493) +{ + UINT8 old_clk = m_lastclk; + m_lastclk = INPVAL(m_clk); + + if (UNEXPECTED(INPVAL(m_R1) & INPVAL(m_R2))) + { + if (EXPECTED(m_cnt > 0)) + { + m_cnt = 0; + m_QA.setTo(0, 40); + m_QB.setTo(0, 40); + m_QC.setTo(0, 40); + m_QD.setTo(0, 40); + } + } + else if (EXPECTED(old_clk & !m_lastclk)) + { + m_cnt++; + m_cnt &= 0x0f; + update_outputs(); + } +} + +NETLIB_FUNC_VOID(nic7493, update_outputs) +{ + if (m_cnt & 1) + m_QA.setToNoCheck(1, 16); + else + { + m_QA.setToNoCheck(0, 16); + switch (m_cnt) + { + case 0x00: + m_QB.setToNoCheck(0, 34); + m_QC.setToNoCheck(0, 48); + m_QD.setToNoCheck(0, 70); + break; + case 0x02: + case 0x06: + case 0x0A: + case 0x0E: + m_QB.setToNoCheck(1, 34); + break; + case 0x04: + case 0x0C: + m_QB.setToNoCheck(0, 34); + m_QC.setToNoCheck(1, 48); + break; + case 0x08: + m_QB.setToNoCheck(0, 34); + m_QC.setToNoCheck(0, 48); + m_QD.setToNoCheck(1, 70); + break; + } + } +} + + +NETLIB_START(nic74107A) +{ + register_input("CLK", &m_clk); + register_input("J", &m_J, NET_INP_TYPE_PASSIVE); + register_input("K", &m_K, NET_INP_TYPE_PASSIVE); + register_input("CLRQ", &m_clrQ); + register_output("Q", &m_Q); + register_output("QQ", &m_QQ); + + m_lastclk = 0; + m_Q.initial(0); + m_QQ.initial(1); +} + +INLINE void nic74107A_newstate(UINT8 state, net_output_t &Q, net_output_t &QQ) +{ + if (state != Q.Q()) + { + Q.setToNoCheck(state, state ? 40 : 25); + QQ.setToNoCheck(!state, state ? 25 : 40); + } +} + +NETLIB_UPDATE(nic74107A) +{ + UINT8 oclk = m_lastclk; + m_lastclk = INPVAL(m_clk); + + if (!INPVAL(m_clrQ)) + nic74107A_newstate(0, m_Q, m_QQ); + else if (oclk & !m_lastclk) + { + if (EXPECTED(INPVAL(m_J) & INPVAL(m_K))) + nic74107A_newstate(!m_Q.Q(), m_Q, m_QQ); + else if (!INPVAL(m_J) & INPVAL(m_K)) + nic74107A_newstate(0, m_Q, m_QQ); + else if (INPVAL(m_J) & !INPVAL(m_K)) + nic74107A_newstate(1, m_Q, m_QQ); + } +} + +NETLIB_START(nic74153) +{ + register_input("A1", &m_I[0]); + register_input("A2", &m_I[1]); + register_input("A3", &m_I[2]); + register_input("A4", &m_I[3]); + register_input("A", &m_A); + register_input("B", &m_B); + register_input("GA", &m_GA); + + register_output("AY", &m_AY); +} + +NETLIB_UPDATE(nic74153) +{ + if (!INPVAL(m_GA)) + { + UINT8 chan = (INPVAL(m_A) | (INPVAL(m_B)<<1)); + m_AY.setTo(INPVAL(m_I[chan])); + } + else + m_AY.clear(); +} + +NETLIB_START(nic9316) +{ + m_lastclk = 0; + m_cnt = 0; + + register_input("CLK", &m_clk); + register_input("ENP", &m_ENP, NET_INP_TYPE_PASSIVE); + register_input("ENT", &m_ENT); + register_input("CLRQ", &m_CLRQ); + register_input("LOADQ", &m_LOADQ, NET_INP_TYPE_PASSIVE); + register_input("A", &m_A, NET_INP_TYPE_PASSIVE); + register_input("B", &m_B, NET_INP_TYPE_PASSIVE); + register_input("C", &m_C, NET_INP_TYPE_PASSIVE); + register_input("D", &m_D, NET_INP_TYPE_PASSIVE); + + register_output("QA", &m_QA); + register_output("QB", &m_QB); + register_output("QC", &m_QC); + register_output("QD", &m_QD); + register_output("RC", &m_RC); +} + +NETLIB_UPDATE(nic9316) +{ + UINT8 old_clk = m_lastclk; + m_lastclk = INPVAL(m_clk); + + if (EXPECTED(INPVAL(m_CLRQ))) + { + if (EXPECTED(!old_clk & m_lastclk)) + { + if (EXPECTED(INPVAL(m_LOADQ))) + { + if (EXPECTED(INPVAL(m_ENP) & INPVAL(m_ENT))) + { + m_cnt = ( m_cnt + 1) & 0x0f; + update_outputs(); + } + } + else + { + m_cnt = (INPVAL(m_D) << 3) | (INPVAL(m_C) << 2) | (INPVAL(m_B) << 1) | (INPVAL(m_A) << 0); + update_outputs_all(); + } + } + m_RC.setTo((INPVAL(m_ENT) & (m_cnt == 0x0f)), 20); + } + else if (m_cnt>0) + { + m_cnt = 0; + update_outputs(); + m_RC.setTo(0, 20); + } +} + +NETLIB_FUNC_VOID(nic9316, update_outputs_all) +{ + m_QA.setTo((m_cnt >> 0) & 1, 20); + m_QB.setTo((m_cnt >> 1) & 1, 20); + m_QC.setTo((m_cnt >> 2) & 1, 20); + m_QD.setTo((m_cnt >> 3) & 1, 20); +} + +NETLIB_FUNC_VOID(nic9316, update_outputs) +{ +#if 0 + m_QA.setTo((m_cnt >> 0) & 1, 20); + m_QB.setTo((m_cnt >> 1) & 1, 20); + m_QC.setTo((m_cnt >> 2) & 1, 20); + m_QD.setTo((m_cnt >> 3) & 1, 20); +#else + if (m_cnt & 1) + m_QA.setToNoCheck(1, 20); + else + { + m_QA.setToNoCheck(0, 20); + switch (m_cnt) + { + case 0x00: + m_QB.setToNoCheck(0, 20); + m_QC.setToNoCheck(0, 20); + m_QD.setToNoCheck(0, 20); + break; + case 0x02: + case 0x06: + case 0x0A: + case 0x0E: + m_QB.setToNoCheck(1, 20); + break; + case 0x04: + case 0x0C: + m_QB.setToNoCheck(0, 20); + m_QC.setToNoCheck(1, 20); + break; + case 0x08: + m_QB.setToNoCheck(0, 20); + m_QC.setToNoCheck(0, 20); + m_QD.setToNoCheck(1, 20); + break; + } + + } +#endif +} + +#define ENTRY(_nic, _name) new net_dev_t_factory< _nic >( # _name, # _nic ), + +static net_dev_t_base_factory *netregistry[] = +{ + ENTRY(netdev_const, NETDEV_CONST) + ENTRY(netdev_input, NETDEV_INPUT) + ENTRY(netdev_callback, NETDEV_CALLBACK) + ENTRY(nicMultiSwitch, NETDEV_SWITCH2) + ENTRY(netdev_delay_lh, NETDEV_DELAY_RAISE) + ENTRY(nicRSFF, NETDEV_RSFF) + ENTRY(nic7400, TTL_7400_NAND) + ENTRY(nic7402, TTL_7402_NOR) + ENTRY(nic7404, TTL_7404_INVERT) + ENTRY(nic7410, TTL_7410_NAND) + ENTRY(nic7420, TTL_7420_NAND) + ENTRY(nic7425, TTL_7425_NOR) + ENTRY(nic7427, TTL_7427_NOR) + ENTRY(nic7430, TTL_7430_NAND) + ENTRY(nic7450, TTL_7450_ANDORINVERT) + ENTRY(nic7486, TTL_7486_XOR) + ENTRY(nic7448, TTL_7448) + ENTRY(nic7474, TTL_7474) + ENTRY(nic7483, TTL_7483) + ENTRY(nic7490, TTL_7490) + ENTRY(nic7493, TTL_7493) + ENTRY(nic74107, TTL_74107) + ENTRY(nic74107A, TTL_74107A) + ENTRY(nic74153, TTL_74153) + ENTRY(nic9316, TTL_9316) + ENTRY(nicNE555N_MSTABLE, NE555N_MSTABLE) + NULL +}; + +net_dev_t *net_create_device_by_classname(const char *classname, netlist_setup_t *setup, const char *icname) +{ + net_dev_t_base_factory **p = &netregistry[0]; + while (p != NULL) + { + if (strcmp((*p)->classname(), classname) == 0) + return (*p)->Create(setup, icname); + p++; + } + fatalerror("Class %s required for IC %s not found!", classname, icname); +} + +net_dev_t *net_create_device_by_name(const char *name, netlist_setup_t *setup, const char *icname) +{ + net_dev_t_base_factory **p = &netregistry[0]; + while (p != NULL) + { + if (strcmp((*p)->name(), name) == 0) + return (*p)->Create(setup, icname); + p++; + } + fatalerror("Class %s required for IC %s not found!", name, icname); +} diff --git a/src/emu/machine/net_lib.h b/src/emu/machine/net_lib.h new file mode 100644 index 00000000000..01b889f52e8 --- /dev/null +++ b/src/emu/machine/net_lib.h @@ -0,0 +1,471 @@ +/*************************************************************************** + + net_lib.h + + Discrete netlist implementation. + +**************************************************************************** + + Couriersud reserves the right to license the code under a less restrictive + license going forward. + + Copyright Nicola Salmoria and the MAME team + All rights reserved. + + Redistribution and use of this code or any derivative works are permitted + provided that the following conditions are met: + + * Redistributions may not be sold, nor may they be used in a commercial + product or activity. + + * Redistributions that are modified from the original source must include the + complete source code, including the source code for all components used by a + binary built from the modified sources. However, as a special exception, the + source code distributed need not include anything that is normally distributed + (in either source or binary form) with the major components (compiler, kernel, + and so on) of the operating system on which the executable runs, unless that + component itself accompanies the executable. + + * Redistributions must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + +****************************************************************************/ + +#ifndef NET_LIB_H +#define NET_LIB_H + +#include "netlist.h" + +// ---------------------------------------------------------------------------------------- +// Special chips +// ---------------------------------------------------------------------------------------- + +#define NETDEV_CONST(_name, _v) \ + NET_REGISTER_DEV(netdev_const, _name) \ + NETDEV_PARAM(_name.CONST, _v) \ + +#define NETDEV_INPUT(_name) \ + NET_REGISTER_DEV(netdev_input, _name) \ + +#define NETDEV_CALLBACK(_name, _IN) \ + NET_REGISTER_DEV(netdev_callback, _name) \ + NET_CONNECT(_name, IN, _IN) \ + +#define NETDEV_SWITCH2(_name, _i1, _i2) \ + NET_REGISTER_DEV(nicMultiSwitch, _name) \ + NET_CONNECT(_name, i1, _i1) \ + NET_CONNECT(_name, i2, _i2) \ + +#define NETDEV_DELAY_RISE(_name, _CLK, _D) \ + NET_REGISTER_DEV(netdev_delay_lh, _name) \ + NET_CONNECT(_name, CLK, _CLK) \ + NET_CONNECT(_name, D, _D) \ + +#define NETDEV_RSFF(_name, _S, _R) \ + NET_REGISTER_DEV(nicRSFF, _name) \ + NET_CONNECT(_name, S, _S) \ + NET_CONNECT(_name, R, _R) \ + + +// ---------------------------------------------------------------------------------------- +// 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) \ + +#define TTL_7404_INVERT(_name, _I1) \ + NET_REGISTER_DEV(nic7404, _name) \ + NET_CONNECT(_name, I1, _I1) \ + +#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) \ + +#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) \ + +#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) \ + +#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) \ + +#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) \ + +#define TTL_7450_ANDORINVERT(_name, _I1, _I2, _I3, _I4) \ + NET_REGISTER_DEV(nic7450, _name) \ + NET_CONNECT(_name, I1, _I1) \ + NET_CONNECT(_name, I2, _I2) \ + NET_CONNECT(_name, I3, _I3) \ + NET_CONNECT(_name, I4, _I4) \ + +#define TTL_7486_XOR(_name, _I1, _I2) \ + NET_REGISTER_DEV(nic7486, _name) \ + NET_CONNECT(_name, I1, _I1) \ + NET_CONNECT(_name, I2, _I2) \ + +#define TTL_7448(_name, _A0, _A1, _A2, _A3, _LTQ, _BIQ, _RBIQ) \ + NET_REGISTER_DEV(nic7448, _name) \ + NET_CONNECT(_name, A0, _A0) \ + NET_CONNECT(_name, A1, _A1) \ + NET_CONNECT(_name, A2, _A2) \ + NET_CONNECT(_name, A3, _A3) \ + NET_CONNECT(_name, LTQ, _LTQ) \ + NET_CONNECT(_name, BIQ, _BIQ) \ + NET_CONNECT(_name, RBIQ, _RBIQ) \ + +#define TTL_7474(_name, _CLK, _D, _CLRQ, _PREQ) \ + NET_REGISTER_DEV(nic7474, _name) \ + NET_CONNECT(_name, CLK, _CLK) \ + NET_CONNECT(_name, D, _D) \ + NET_CONNECT(_name, CLRQ, _CLRQ) \ + NET_CONNECT(_name, PREQ, _PREQ) \ + +#define TTL_7483(_name, _A1, _A2, _A3, _A4, _B1, _B2, _B3, _B4, _CI) \ + NET_REGISTER_DEV(nic7483, _name) \ + NET_CONNECT(_name, A1, _A1) \ + NET_CONNECT(_name, A2, _A2) \ + NET_CONNECT(_name, A3, _A3) \ + NET_CONNECT(_name, A4, _A4) \ + NET_CONNECT(_name, B1, _B1) \ + NET_CONNECT(_name, B2, _B2) \ + NET_CONNECT(_name, B3, _B3) \ + NET_CONNECT(_name, B4, _B4) \ + NET_CONNECT(_name, CI, _CI) \ + +#define TTL_7490(_name, _CLK, _R1, _R2, _R91, _R92) \ + NET_REGISTER_DEV(nic7490, _name) \ + NET_CONNECT(_name, CLK, _CLK) \ + NET_CONNECT(_name, R1, _R1) \ + NET_CONNECT(_name, R2, _R2) \ + NET_CONNECT(_name, R91, _R91) \ + NET_CONNECT(_name, R92, _R92) \ + +#define TTL_7493(_name, _CLK, _R1, _R2) \ + NET_REGISTER_DEV(nic7493, _name) \ + NET_CONNECT(_name, CLK, _CLK) \ + NET_CONNECT(_name, R1, _R1) \ + NET_CONNECT(_name, R2, _R2) \ + +#define TTL_74107A(_name, _CLK, _J, _K, _CLRQ) \ + NET_REGISTER_DEV(nic74107A, _name) \ + NET_CONNECT(_name, CLK, _CLK) \ + NET_CONNECT(_name, J, _J) \ + NET_CONNECT(_name, K, _K) \ + NET_CONNECT(_name, CLRQ, _CLRQ) \ + +#define TTL_74107(_name, _CLK, _J, _K, _CLRQ) \ + TTL_74107A(_name, _CLK, _J, _K, _CLRQ) + +#define TTL_74153(_name, _A1, _A2, _A3, _A4, _A, _B, _GA) \ + NET_REGISTER_DEV(nic74153, _name) \ + NET_CONNECT(_name, A1, _A1) \ + NET_CONNECT(_name, A2, _A2) \ + NET_CONNECT(_name, A3, _A3) \ + NET_CONNECT(_name, A4, _A4) \ + NET_CONNECT(_name, A, _A) \ + NET_CONNECT(_name, B, _B) \ + NET_CONNECT(_name, GA, _GA) \ + +#define TTL_9316(_name, _CLK, _ENP, _ENT, _CLRQ, _LOADQ, _A, _B, _C, _D) \ + NET_REGISTER_DEV(nic9316, _name) \ + NET_CONNECT(_name, CLK, _CLK) \ + NET_CONNECT(_name, ENP, _ENP) \ + NET_CONNECT(_name, ENT, _ENT) \ + NET_CONNECT(_name, CLRQ, _CLRQ) \ + NET_CONNECT(_name, LOADQ,_LOADQ) \ + NET_CONNECT(_name, A, _A) \ + NET_CONNECT(_name, B, _B) \ + NET_CONNECT(_name, C, _C) \ + NET_CONNECT(_name, D, _D) \ + + +#define NE555N_MSTABLE(_name, _TRIG) \ + NET_REGISTER_DEV(nicNE555N_MSTABLE, _name) \ + NET_CONNECT(_name, TRIG, _TRIG) \ + +// ---------------------------------------------------------------------------------------- +// Special support devices ... +// ---------------------------------------------------------------------------------------- + +NETLIB_DEVICE_WITH_PARAMS(netdev_const, + net_output_t m_Q; + net_param_t m_const; +); + +NETLIB_DEVICE(netdev_input, + net_output_t m_Q; +); + + +// ---------------------------------------------------------------------------------------- +// Special devices ... +// ---------------------------------------------------------------------------------------- + +/* This class is an artificial delay circuit delaying a signal until the next low to high transition + * this is needed by pong to model delays in the hblank circuit + */ + +NETLIB_DEVICE(netdev_delay_lh, + net_input_t m_clk; + net_input_t m_D; + + net_sig_t m_lastclk; + + net_output_t m_Q; +); + +NETLIB_DEVICE_WITH_PARAMS(nicMultiSwitch, + net_input_t m_I[8]; + + net_output_t m_Q; + net_output_t m_low; + + net_param_t m_POS; + + int m_position; +); + +NETLIB_DEVICE(nicRSFF, + net_input_t m_S; + net_input_t m_R; + + net_output_t m_Q; + net_output_t m_QQ; +); + +// ---------------------------------------------------------------------------------------- +// Standard devices ... +// ---------------------------------------------------------------------------------------- + +NETLIB_DEVICE_WITH_PARAMS(nicNE555N_MSTABLE, + + ATTR_HOT void timer_cb(INT32 timer_id); + + net_input_t m_trigger; + + UINT8 m_last; + UINT8 m_fired; + double m_time; + + net_output_t m_Q; + + netlist_base_timer_t *m_timer; + net_param_t m_R; + net_param_t m_C; + net_param_t m_VS; + net_param_t m_VL; + net_param_t m_VT; +); + +NETLIB_SIGNAL(nic7400, 2) +NETLIB_SIGNAL(nic7402, 2) +NETLIB_SIGNAL(nic7404, 1) +NETLIB_SIGNAL(nic7410, 3) +NETLIB_SIGNAL(nic7420, 4) +NETLIB_SIGNAL(nic7425, 4) +NETLIB_SIGNAL(nic7427, 3) +NETLIB_SIGNAL(nic7430, 8) +NETLIB_SIGNAL(nic7450, 4) + +NETLIB_DEVICE(nic7474, + net_input_t m_clk; + net_input_t m_D; + net_input_t m_clrQ; + net_input_t m_preQ; + + net_sig_t m_lastclk; + + net_output_t m_Q; + net_output_t m_QQ; +); + +NETLIB_SIGNAL(nic7486, 2) + +/* 74107 does latch data during high ! + * For modelling purposes, we assume 74107 and 74107A are the same + */ + + +NETLIB_DEVICE(nic74107A, + net_input_t m_clk; + net_input_t m_J; + net_input_t m_K; + net_input_t m_clrQ; + + net_sig_t m_lastclk; + + net_output_t m_Q; + net_output_t m_QQ; +); + +class nic74107 : public nic74107A +{ +public: + nic74107(netlist_setup_t *parent, const char *name) + : nic74107A(parent, name) {} + +}; + + +NETLIB_DEVICE(nic7493, + ATTR_HOT void update_outputs(); + + net_input_t m_R1; + net_input_t m_R2; + net_input_t m_clk; + + UINT8 m_lastclk; + UINT8 m_cnt; + + net_output_t m_QA; + net_output_t m_QB; + net_output_t m_QC; + net_output_t m_QD; +); + +NETLIB_DEVICE(nic7490, + ATTR_HOT void update_outputs(); + + net_input_t m_R1; + net_input_t m_R2; + net_input_t m_R91; + net_input_t m_R92; + net_input_t m_clk; + + net_sig_t m_lastclk; + UINT8 m_cnt; + + net_output_t m_QA; + net_output_t m_QB; + net_output_t m_QC; + net_output_t m_QD; +); + +/* ripple-carry counter on low-high clock transition */ +NETLIB_DEVICE(nic9316, + ATTR_HOT void update_outputs_all(); + ATTR_HOT void update_outputs(); + + net_input_t m_clk; + net_input_t m_ENP; + net_input_t m_ENT; + net_input_t m_CLRQ; + net_input_t m_LOADQ; + net_input_t m_A; + net_input_t m_B; + net_input_t m_C; + net_input_t m_D; + + UINT8 m_lastclk; + UINT8 m_cnt; + + net_output_t m_QA; + net_output_t m_QB; + net_output_t m_QC; + net_output_t m_QD; + net_output_t m_RC; +); + +NETLIB_DEVICE(nic7483, + net_input_t m_CI; + net_input_t m_A1; + net_input_t m_A2; + net_input_t m_A3; + net_input_t m_A4; + net_input_t m_B1; + net_input_t m_B2; + net_input_t m_B3; + net_input_t m_B4; + net_input_t m_clk; + + UINT8 m_lastr; + + net_output_t m_SA; + net_output_t m_SB; + net_output_t m_SC; + net_output_t m_SD; + net_output_t m_CO; + +); + +/* one half of a nic74153 */ + +NETLIB_DEVICE(nic74153, + net_input_t m_I[4]; + net_input_t m_A; + net_input_t m_B; + net_input_t m_GA; + + net_output_t m_AY; +); + +NETLIB_DEVICE(nic7448, + static const UINT8 tab7448[16][7]; + + net_input_t m_A0; + net_input_t m_A1; + net_input_t m_A2; + net_input_t m_A3; + net_input_t m_LTQ; + net_input_t m_RBIQ; + net_input_t m_BIQ; + + UINT8 m_state; + + net_output_t m_a; + net_output_t m_b; + net_output_t m_c; + net_output_t m_d; + net_output_t m_e; + net_output_t m_f; + net_output_t m_g; +); + + + +#endif diff --git a/src/emu/machine/netlist.c b/src/emu/machine/netlist.c new file mode 100644 index 00000000000..5dc87b9a168 --- /dev/null +++ b/src/emu/machine/netlist.c @@ -0,0 +1,798 @@ +/*************************************************************************** + + netlist.c + + Discrete netlist implementation. + +**************************************************************************** + + Couriersud reserves the right to license the code under a less restrictive + license going forward. + + Copyright Nicola Salmoria and the MAME team + All rights reserved. + + Redistribution and use of this code or any derivative works are permitted + provided that the following conditions are met: + + * Redistributions may not be sold, nor may they be used in a commercial + product or activity. + + * Redistributions that are modified from the original source must include the + complete source code, including the source code for all components used by a + binary built from the modified sources. However, as a special exception, the + source code distributed need not include anything that is normally distributed + (in either source or binary form) with the major components (compiler, kernel, + and so on) of the operating system on which the executable runs, unless that + component itself accompanies the executable. + + * Redistributions must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + +****************************************************************************/ + +#include "netlist.h" + +//============================================================ +// DEBUGGING +//============================================================ + +#define VERBOSE (0) +#define KEEP_STATISTICS (0) + + +#if KEEP_STATISTICS && USE_DELEGATES +#error "Statistics only work without delegates!" +#endif + +#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 { atomic_add32((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 + +// ---------------------------------------------------------------------------------------- +// 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) + { + char *n; + skipws(); + if (!*m_p) break; + n = getname('('); + VERBOSE_OUT(("Parser: Device: %s\n", n)); + if (strcmp(n,"NET_ALIAS") == 0) + { + char *alias; + char *out; + m_p++; + skipws(); + alias = getname(','); + m_p++; + skipws(); + out = getname(')'); + m_p++; + VERBOSE_OUT(("Parser: Alias: %s %s\n", alias, out)); + m_setup.register_alias(alias, out); + } + else if (strcmp(n,"NETDEV_PARAM") == 0) + { + char *param; + double val; + m_p++; + skipws(); + param = getname(','); + m_p++; + skipws(); + val = eval_param(); + m_p++; + VERBOSE_OUT(("Parser: Param: %s %f\n", param, val)); + m_setup.find_param(param)->setTo(val); + } + else if (strcmp(n,"NETDEV_CONST") == 0) + { + char *devname; + net_dev_t *dev; + char paramfq[30]; + double val; + m_p++; + skipws(); + devname = getname(','); + dev = net_create_device_by_name(n, &m_setup, devname); + m_setup.register_dev(dev); + m_p++; + skipws(); + val = eval_param(); + m_p++; + strcpy(paramfq, devname); + strcat(paramfq, ".CONST"); + VERBOSE_OUT(("Parser: Const: %s %f\n", devname, val)); + m_setup.find_param(paramfq)->setTo(val); + } + else + { + char *devname; + net_dev_t *dev; + int cnt; + + m_p++; + skipws(); + devname = getname2(',', ')'); + dev = net_create_device_by_name(n, &m_setup, devname); + m_setup.register_dev(dev); + skipws(); + VERBOSE_OUT(("Parser: IC: %s\n", n)); + cnt = 0; + while (*m_p != ')') + { + m_p++; + skipws(); + n = getname2(',', ')'); + VERBOSE_OUT(("Parser: ID: %s %s\n", n, dev->m_inputs.item(cnt))); + m_setup.register_link(dev->m_inputs.item(cnt), n); + skipws(); + cnt++; + //return 0; + } + if (cnt != dev->m_inputs.count() && !dev->variable_input_count()) + fatalerror("netlist: input count mismatch for %s - expected %d found %d\n", devname, dev->m_inputs.count(), cnt); + m_p++; + } + } + } + +private: + void skipeol() + { + while (*m_p) + { + if (*m_p == 10) + { + 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; + } + } + } + + char *getname(char sep) + { + static char buf[30]; + char *p1 = buf; + + while (*m_p != sep) + *p1++ = *m_p++; + *p1 = 0; + return core_strdup(buf); + } + + char *getname2(char sep1, char sep2) + { + static char buf[30]; + char *p1 = buf; + + while ((*m_p != sep1) && (*m_p != sep2)) + *p1++ = *m_p++; + *p1 = 0; + return core_strdup(buf); + } + + 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 != ')')) + exit(0); + if (f>0) + e++; + m_p = e; + return ret * facs[f]; + } + + char * m_p; + netlist_setup_t &m_setup; + +}; + + +// ---------------------------------------------------------------------------------------- +// netlist_base_t +// ---------------------------------------------------------------------------------------- + + +netlist_base_t::netlist_base_t(bool sub_cycle_exact) + //m_output_list(ttl_list_t(2048)), + : m_current(0), m_divisor(32), m_sub_cycle_exact(sub_cycle_exact), m_gatedelay(100), m_clockfreq(1000000) +{ + m_netlist_mask = NET_LIST_MASK; + reset_lists(); +} + +netlist_base_t::~netlist_base_t() +{ +} + +void netlist_base_t::set_clock_freq(int clockfreq) +{ + m_clockfreq = clockfreq; + m_divisor = 1000000000L * 100L / (m_clockfreq) / m_gatedelay; + VERBOSE_OUT(("Divisor %d\n", m_divisor)); +} + +void netlist_base_t::set_gatedelay(int gatedelay) +{ + m_gatedelay = gatedelay; + m_divisor = 1000000000L * 100L / (m_clockfreq) / m_gatedelay; + VERBOSE_OUT(("Divisor %d\n", m_divisor)); +} + +ATTR_HOT inline void netlist_base_t::process_list(void) +{ + net_list_t &list = m_output_list[m_sub_cycle_exact ? m_current : 0]; +#if 0 + net_output_t * RESTRICT * RESTRICT first; + net_output_t * RESTRICT * RESTRICT last; + + first = list.first(); + last = list.last(); + while (first <= last) + { + net_output_t * RESTRICT * RESTRICT out = first; + while (out <= last) + { + (*out)->update_out(); + (*out)->update_devs(); + out++; + } + first = last + 1; + last = list.last(); + } +#else + net_output_t * RESTRICT * RESTRICT out; + + out = list.first(); + while (out <= list.last()) + { + (*out)->update_out(); + (*out)->update_devs(); + out++; + } +#endif + reset_list(); + + if (m_sub_cycle_exact) + m_current = (m_current + 1) & m_netlist_mask; +} + +// ---------------------------------------------------------------------------------------- +// netlist_setup_t +// ---------------------------------------------------------------------------------------- + +netlist_setup_t::netlist_setup_t(netlist_base_t &netlist) + //m_output_list(ttl_list_t(2048)), + : m_netlist(netlist) +{ +} + +netlist_setup_t::~netlist_setup_t() +{ +} + + +net_dev_t *netlist_setup_t::register_dev(net_dev_t *dev) +{ + if (!(m_devices.add(dev->name(), dev, false)==TMERR_NONE)) + fatalerror("Error adding %s to device list\n", dev->name()); + dev->start(); + return dev; +} + +template +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 char *name) +{ + net_dev_t *dev = m_devices.find(name); + astring temp = name; + if (dev == NULL) + fatalerror("Device %s does not exist\n", name); + + temp.cat("."); + + remove_start_with(m_inputs, temp); + remove_start_with(m_outputs, temp); + remove_start_with(m_params, temp); + remove_start_with(m_links, temp); + m_devices.remove(name); +} + +void netlist_setup_t::register_callback(const char *devname, net_output_delegate delegate) +{ + netdev_callback *dev = (netdev_callback *) m_devices.find(devname); + if (dev == NULL) + fatalerror("did not find device %s\n", devname); + dev->register_callback(delegate); +} + +void netlist_setup_t::register_alias(const char *alias, const char *out) +{ + if (!(m_alias.add(alias, new astring(out), false)==TMERR_NONE)) + fatalerror("Error adding alias %s to alias list\n", alias); +} + +void netlist_setup_t::register_output(const char *name, net_output_t *out) +{ + VERBOSE_OUT(("out %s\n", name)); + if (!(m_outputs.add(name, out, false)==TMERR_NONE)) + fatalerror("Error adding output %s to output list\n", name); +} + +void netlist_setup_t::register_input(const char *name, net_input_t *inp, net_input_type type) +{ + net_input_setup_t *setup_inp = new net_input_setup_t(inp, type); + VERBOSE_OUT(("input %s\n", name)); + if (!(m_inputs.add(name, setup_inp, false) == TMERR_NONE)) + fatalerror("Error adding input %s to input list\n", name); +} + +void netlist_setup_t::register_link(const char *sin, const char *sout) +{ + VERBOSE_OUT(("link %s <== %s\n", sin, sout)); + if (!(m_links.add(sin, new astring(sout), false)==TMERR_NONE)) + fatalerror("Error adding link %s<==%s to link list\n", sin, sout); +} + + +void netlist_setup_t::register_param(const char *sname, net_param_t *param) +{ + astring temp = param->ttl_dev()->name(); + temp.cat("."); + temp.cat(sname); + if (!(m_params.add(temp, param, false)==TMERR_NONE)) + fatalerror("Error adding parameter %s to parameter list\n", sname); +} + + +const char *netlist_setup_t::resolve_alias(const char *name) const +{ + const astring *ret = m_alias.find(name); + if (ret != NULL) + return ret->cstr(); + return name; +} + +net_output_t *netlist_setup_t::find_output_exact(const char *outname_in) +{ + net_output_t *ret = m_outputs.find(outname_in); + + return ret; +} + +net_output_t *netlist_setup_t::find_output(const char *outname_in) +{ + const char *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!", outname_in, outname); + VERBOSE_OUT(("Found input %s\n", outname)); + return ret; +} + +net_param_t *netlist_setup_t::find_param(const char *param_in) +{ + const char *outname = resolve_alias(param_in); + net_param_t *ret; + + ret = m_params.find(outname); + if (ret == NULL) + fatalerror("parameter %s(%s) not found!", param_in, outname); + VERBOSE_OUT(("Found parameter %s\n", outname)); + return ret; +} + +void netlist_setup_t::resolve_inputs(void) +{ + VERBOSE_OUT(("Resolving ...\n")); + 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_setup_t *in = m_inputs.find(sin); + int p = sin.find("."); + const char *devname = sin.substr(0, p); + net_dev_t *dev = m_devices.find(devname); + net_output_t *out = find_output(sout->cstr() ); + + (*in->inp()).o = GETINPPTR(*out); + //in->inp()->v = out->Q_ptr(); + if (in->type() == NET_INP_TYPE_ACTIVE) + out->register_con(dev); + } + + step_all_devices(); + //reset_list(); + //process_list(); +} + +void netlist_setup_t::step_all_devices() +{ + m_netlist.reset_list(); + + for (tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry)) + { + net_dev_t &dev = *entry->object(); + dev.update_param(); + dev.update(); + + for (tagmap_output_t::entry_t *entry = m_outputs.first(); entry != NULL; entry = m_outputs.next(entry)) + { + net_output_t &out = *entry->object(); + out.update_out(); + } + m_netlist.reset_lists(); + } +} + +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)) + { + printf("Device %20s : %12d %15ld\n", entry->object()->name(), entry->object()->stat_count, (long int) entry->object()->total_time / (entry->object()->stat_count + 1)); + } + } +} + + +// ---------------------------------------------------------------------------------------- +// net_dev_t +// ---------------------------------------------------------------------------------------- + +net_dev_t::~net_dev_t() +{ +} + +ATTR_HOT void net_dev_t::update_timed() +{ + inc_stat(&stat_count); + begin_timing(total_time); + update(); + end_timing(total_time); +} + +void net_dev_t::register_output(const char *name, net_output_t *port) +{ + astring temp = this->name(); + temp.cat("."); + temp.cat(name); + port->set_ttl_dev(this); + m_setup->register_output(temp, port); +} + +void net_dev_t::register_input(const char *name, net_input_t *inp, net_input_type type) +{ + astring temp = this->name(); + temp.cat("."); + temp.cat(name); + m_inputs.add(core_strdup(temp.cstr())); + m_setup->register_input(temp, inp, type); +} + +void net_dev_t::register_param(const char *name, net_param_t *param, double initialVal) +{ + param->set_ttl_dev(this); + param->initial(initialVal); + m_setup->register_param(name, param); +} + +// ---------------------------------------------------------------------------------------- +// net_output_t +// ---------------------------------------------------------------------------------------- + +net_output_t::net_output_t() +{ +#if USE_DELEGATES + //m_cons = global_alloc_array_clear(net_update_delegate, 32); +#else + // m_cons = global_alloc_array_clear(net_dev_t *, 32); +#endif + //m_Q = parent.alloc_sig(); + //m_new_Q = parent.alloc_sig(); + m_num_cons = 0; + m_Q = 0; + m_new_Q = m_Q; +} + +ATTR_COLD void net_output_t::set_ttl_dev(net_dev_t *dev) +{ + m_ttldev = dev; + m_netlist = &dev->setup()->netlist(); +} + + +ATTR_COLD void net_output_t::register_con(net_dev_t *dev) +{ + assert(m_num_cons<32); +#if USE_DELEGATES + net_update_delegate aDelegate = net_update_delegate(&net_dev_t::update, "update", dev); + for (int i=0; i < m_num_cons; i++) + if (m_cons[i] == aDelegate) + return; + m_cons[m_num_cons++] = aDelegate; +#else + for (int i=0; i < m_num_cons; i++) + if (m_cons[i] == dev) + return; + m_cons[m_num_cons++] = dev; +#endif +} + +ATTR_HOT inline void net_output_t::update_devs() +{ +#if USE_DELEGATES + + net_update_delegate *s = m_cons; + net_update_delegate *e = s + m_num_cons; + + while (supdate_timed(); +#else + while (supdate(); +#endif +#endif +} + +NETLIB_UPDATE(netdev_callback) +{ + // FIXME: Remove after device cleanup + if (!m_callback.isnull()) + m_callback(INPVAL(m_in)); +} + +// ---------------------------------------------------------------------------------------- +// netlist_mame_device +// ---------------------------------------------------------------------------------------- + + + +const device_type NETLIST = &device_creator; + +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), + device_execute_interface(mconfig, *this) +{ + m_clock = clock; +} + +void netlist_mame_device::static_set_subcycles(device_t &device, int subcycles) +{ + netlist_mame_device &netlist = downcast(device); + + assert((subcycles & 1) == 0); + assert( subcycles > 0); + + netlist.m_subcycles = subcycles; +} + +void netlist_mame_device::static_set_constructor(device_t &device, void (*setup_func)(netlist_setup_t &)) +{ + netlist_mame_device &netlist = downcast(device); + netlist.m_setup_func = setup_func; +} + +void netlist_mame_device::device_config_complete() +{ +} + +void netlist_mame_device::device_start() +{ + + //double dt = clocks_to_attotime(1).as_double(); + m_netlist = global_alloc_clear(netlist_t(*this, m_subcycles > 2)); + m_netlist->set_clock_freq(m_clock * m_subcycles); + + m_setup = global_alloc_clear(netlist_setup_t(*m_netlist)); + + m_setup_func(*m_setup); + + bool allok = true; + for (on_device_start **ods = m_device_start_list.first(); ods <= m_device_start_list.last(); ods++) + allok &= (*ods)->OnDeviceStart(); + + if (!allok) + fatalerror("required elements not found\n"); + + m_setup->resolve_inputs(); + + //m_clockcnt = 0; + + m_clock_input = m_setup->find_output("clk"); + + //save_item(NAME(m_clockcnt)); + save_state(); + /* TODO: we have to save the round robin queue as well */ + + // set our instruction counter + m_icountptr = &m_icount; + m_ss = SubCycles() / 2; + m_clk = 0; +} + +void netlist_mame_device::device_reset() +{ +} + +void netlist_mame_device::device_stop() +{ + m_setup->print_stats(); +} + +void netlist_mame_device::device_post_load() +{ + +} + +void netlist_mame_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + +} + +void netlist_mame_device::save_state() +{ + for (netlist_setup_t::tagmap_output_t::entry_t *entry = m_setup->m_outputs.first(); entry != NULL; entry = m_setup->m_outputs.next(entry)) + { + save_item(*entry->object()->Q_ptr(), entry->tag().cstr(), 0); + save_item(*entry->object()->new_Q_ptr(), entry->tag().cstr(), 1); + } +} + +UINT64 netlist_mame_device::execute_clocks_to_cycles(UINT64 clocks) const +{ + return clocks * SubCycles(); +} + +UINT64 netlist_mame_device::execute_cycles_to_clocks(UINT64 cycles) const +{ + return cycles / SubCycles(); +} + +ATTR_HOT void netlist_mame_device::execute_run() +{ + //bool check_debugger = ((device_t::machine().debug_flags & DEBUG_FLAG_ENABLED) != 0); + osd_ticks_t a = -osd_ticks(); + UINT8 ssdiv2 = (SubCycles() / 2); + //int p = m_icount; + do + { + // debugging + //m_ppc = m_pc; // copy PC to previous PC + //if (check_debugger) + // debugger_instruction_hook(this, 0); //m_pc); + if (--m_ss == 0) + { + m_ss = ssdiv2; + m_clk = !m_clk; + m_clock_input->setTo(m_clk); + } + m_netlist->process_list(); + m_icount--; + } while (m_icount > 0); + a+=osd_ticks(); + //printf("%ld %d %ld\n", (long) a, p, (long) (a * 1000 / p)); +} + + + diff --git a/src/emu/machine/netlist.h b/src/emu/machine/netlist.h new file mode 100644 index 00000000000..4f24b992905 --- /dev/null +++ b/src/emu/machine/netlist.h @@ -0,0 +1,870 @@ +/*************************************************************************** + + netlist.h + + Discrete netlist implementation. + +**************************************************************************** + + Couriersud reserves the right to license the code under a less restrictive + license going forward. + + Copyright Nicola Salmoria and the MAME team + All rights reserved. + + Redistribution and use of this code or any derivative works are permitted + provided that the following conditions are met: + + * Redistributions may not be sold, nor may they be used in a commercial + product or activity. + + * Redistributions that are modified from the original source must include the + complete source code, including the source code for all components used by a + binary built from the modified sources. However, as a special exception, the + source code distributed need not include anything that is normally distributed + (in either source or binary form) with the major components (compiler, kernel, + and so on) of the operating system on which the executable runs, unless that + component itself accompanies the executable. + + * Redistributions must reproduce the above copyright notice, this list of + conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + +****************************************************************************/ + +#ifndef NETLIST_H +#define NETLIST_H + +#include "emu.h" +#include "tagmap.h" + +//============================================================ +// SETUP +//============================================================ + +#define USE_DELEGATES (1) +#define USE_DOUBLE (0) + +#define NET_LIST_SIZE (32) +#define NET_LIST_MASK (0x1f) + +//============================================================ +// 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)->setTo(_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.netlist()).machine().root_device().memregion(_name)->base()); \ + +#if defined(__GNUC__) && (__GNUC__ >= 3) +#define ATTR_ALIGN __attribute__ ((aligned(64))) +#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 ATTR_ALIGN void _chip :: start(void) +#define NETLIB_UPDATE_PARAM(_chip) ATTR_HOT ATTR_ALIGN void _chip :: update_param(void) +#define NETLIB_FUNC_VOID(_chip, _name) ATTR_HOT ATTR_ALIGN inline void _chip :: _name (void) + +#define NETLIB_TIMER_CALLBACK(_chip) ATTR_HOT void _chip :: timer_cb(INT32 timer_id) + +#define NETLIB_SIGNAL(_name, _num_input) \ + class _name : public net_signal_t< _num_input > \ + { \ + public: \ + _name (netlist_setup_t *parent, const char *name) \ + : net_signal_t(parent, name) { } \ + ATTR_HOT void update(); \ + }; \ + +#define NETLIB_DEVICE(_name, _priv) \ + class _name : public net_dev_t \ + { \ + public: \ + _name (netlist_setup_t *parent, const char *name) \ + : net_dev_t(parent, name) { } \ + ATTR_HOT void update(); \ + ATTR_COLD void start(); \ + private: \ + _priv \ + } \ + +#define NETLIB_DEVICE_WITH_PARAMS(_name, _priv) \ + class _name : public net_dev_t \ + { \ + public: \ + _name (netlist_setup_t *parent, const char *name) \ + : net_dev_t(parent, name) { } \ + ATTR_HOT void update_param(); \ + ATTR_HOT void update(); \ + ATTR_COLD void start(); \ + private: \ + _priv \ + } \ + +// MAME specific + +#define MCFG_NETLIST_ADD(_tag, _clock, _setup, _subcycles) \ + MCFG_DEVICE_ADD(_tag, NETLIST, _clock) \ + MCFG_NETLIST_SUBCYCLES(_subcycles) \ + MCFG_NETLIST_SETUP(_setup) \ + +#define MCFG_NETLIST_REPLACE(_tag, _clock, _setup, _subcycles) \ + MCFG_DEVICE_REPLACE(_tag, NETLIST, _clock) \ + MCFG_NETLIST_SUBCYCLES(_subcycles) \ + MCFG_NETLIST_SETUP(_setup) \ + +#define MCFG_NETLIST_SUBCYCLES(_subcycles) \ + netlist_mame_device::static_set_subcycles(*device, _subcycles); \ + +#define MCFG_NETLIST_SETUP(_setup) \ + netlist_mame_device::static_set_constructor(*device, NETLIST_NAME(_setup)); \ + + +// ---------------------------------------------------------------------------------------- +// Type definitions +// ---------------------------------------------------------------------------------------- + + +enum net_input_type { + NET_INP_TYPE_PASSIVE, + NET_INP_TYPE_ACTIVE +}; + +enum { nst_LOW = 0, nst_HIGH = 1}; +//typedef double net_sig_t; +//enum net_sig_t { nst_LOW = 0, nst_HIGH = 1}; + +// ---------------------------------------------------------------------------------------- +// net_input_t +// ---------------------------------------------------------------------------------------- + +class net_output_t; + +#if !USE_DOUBLE +#if 0 +typedef UINT8 net_sig_t; +#define INPVAL(_x) (*(_x)) +#define GETINPPTR(_x) (_x).Q_ptr() +typedef net_sig_t * RESTRICT net_input_t; +#else +typedef UINT8 net_sig_t; +//#define INPVAL(_x) ((_x)->Q()) +#define INPVAL(_x) INP(_x) +#define GETINPPTR(_x) (&(_x)) +class net_input_t { +public: + net_output_t * RESTRICT o; +}; +#endif +#else +typedef double net_sig_t; +#define INPVAL(_x) ((int)*(_x)) +#define GETINPPTR(_x) (_x).Q_ptr() +typedef net_sig_t * RESTRICT net_input_t; +#endif + + + +typedef delegate net_output_delegate; + +#if USE_DELEGATES +typedef delegate net_update_delegate; +typedef delegate net_register_delegate; +#endif + +class net_dev_t; +class net_param_t; +class netlist_setup_t; +class netlist_base_t; + +// ---------------------------------------------------------------------------------------- +// net_list_t +// ---------------------------------------------------------------------------------------- + +template +struct net_list_t +{ +public: + net_list_t() //(int max_elements = 64) + { + //m_list = global_alloc_array_clear(_ListClass, max_elements); + m_ptr = m_list; + m_ptr--; + } + 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; } + ATTR_HOT inline _ListClass *last() { return m_ptr; } + ATTR_HOT inline _ListClass item(int i) { return m_list[i]; } + inline int count() { 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[_NumElements]; +}; + +// ---------------------------------------------------------------------------------------- +// net_output_t +// ---------------------------------------------------------------------------------------- + +struct net_output_t +{ +public: + net_output_t(); + + ATTR_HOT inline void clear() { set_Q(nst_LOW); } + ATTR_HOT inline void set() { set_Q(nst_HIGH); } + ATTR_HOT inline void setTo(const net_sig_t val) { set_Q(val); } + ATTR_HOT inline void setTo(const net_sig_t val, const UINT8 delay_ns) { set_Q(val,delay_ns); } + ATTR_HOT inline void setToNoCheck(const net_sig_t val) + { + m_new_Q = val; + register_in_list(); + } + + ATTR_HOT inline void setToNoCheck(const net_sig_t val, const UINT8 delay_ns) + { + m_new_Q = val; + register_in_list(delay_ns); + } + + ATTR_COLD void initial(const net_sig_t val) { m_Q = val; m_new_Q = val; } + + ATTR_HOT inline const net_sig_t Q() const { return m_Q; } + + inline net_sig_t *Q_ptr() { return &m_Q; } + inline net_sig_t *new_Q_ptr() { return &m_new_Q; } + + ATTR_COLD void register_con(net_dev_t *dev); + + ATTR_HOT void update_devs(); + + ATTR_HOT inline void update_out() { + m_Q = m_new_Q; + //m_QD = m_new_QD; + } + + ATTR_HOT inline const net_dev_t *ttl_dev() { return m_ttldev; } + + ATTR_COLD void set_ttl_dev(net_dev_t *dev); + +private: + + ATTR_HOT inline void register_in_list(const UINT8 delay_ns); + ATTR_HOT inline void register_in_list(); + + ATTR_HOT inline void set_Q(const net_sig_t newQ) + { + if (newQ != m_new_Q) + { + m_new_Q = newQ; + //m_new_QD = newQ ? 1.0 : 0.0; + register_in_list(); + } + } + + ATTR_HOT inline void set_Q(const net_sig_t newQ, const UINT8 delay_ns) + { + if (newQ != m_new_Q) + { + m_new_Q = newQ; + //m_new_QD = newQ ? 1.0 : 0.0; + register_in_list(delay_ns); + } + } + + net_sig_t m_Q; + net_sig_t m_new_Q; + double m_QD; + double m_new_QD; + netlist_base_t *m_netlist; + int m_num_cons; +#if USE_DELEGATES + net_update_delegate m_cons[32]; +#else + //net_dev_t **m_cons; + net_dev_t *m_cons[32]; +#endif + net_dev_t *m_ttldev; +}; + +// ---------------------------------------------------------------------------------------- +// net_dev_t +// ---------------------------------------------------------------------------------------- + +class net_dev_t +{ +public: + net_dev_t(netlist_setup_t *setup, const char *name) + : m_setup(setup), m_variable_input_count(false), m_name(name) + { + assert(name != NULL); + } + + virtual ~net_dev_t(); + + ATTR_HOT virtual void timer_cb(INT32 timer_id) {} + + const char *name() const { return m_name; } + inline netlist_setup_t *setup() { return m_setup; } + + ATTR_HOT void update_timed(); + + ATTR_HOT virtual void update_param() {} + + ATTR_HOT virtual void update() { } + + ATTR_HOT inline net_sig_t INP(net_input_t &v) { return v.o->Q(); } + + ATTR_COLD virtual void start() {} + + net_list_t m_inputs; + + ATTR_COLD bool variable_input_count() { return m_variable_input_count; } + + /* stats */ + osd_ticks_t total_time; + volatile INT32 stat_count; + +protected: + + void register_output(const char *name, net_output_t *out); + void register_input(const char *name, net_input_t *in, net_input_type type = NET_INP_TYPE_ACTIVE); + void register_param(const char *sname, net_param_t *param, double initialVal = 0.0); + + netlist_setup_t *m_setup; + bool m_variable_input_count; + +private: + + const char *m_name; +}; + + + +class net_param_t +{ +public: + net_param_t() { } + + inline void setTo(const double param) { m_param = param; m_ttldev->update_param(); } + inline void setTo(const int param) { m_param = param; m_ttldev->update_param(); } + inline void initial(const double val) { m_param = val; } + inline void initial(const int val) { m_param = val; } + + inline double Value() { return m_param; } + inline int ValueInt() { return m_param; } + + ATTR_HOT inline const net_dev_t *ttl_dev() { return m_ttldev; } + void set_ttl_dev(net_dev_t *dev) { m_ttldev = dev; } + +private: + + double m_param; + net_dev_t *m_ttldev; +}; + +// ---------------------------------------------------------------------------------------- +// net_signal_t +// ---------------------------------------------------------------------------------------- + +template +class net_signal_t : public net_dev_t +{ +public: + net_signal_t(netlist_setup_t *parent, const char *name) + : net_dev_t(parent, name) { } + + //ATTR_HOT virtual void update() = 0; + 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]); + } + +protected: + net_input_t m_i[_numdev]; + net_output_t m_Q; +}; + +// ---------------------------------------------------------------------------------------- +// netlist_base_timer_t +// ---------------------------------------------------------------------------------------- + +class netlist_base_timer_t +{ +public: + netlist_base_timer_t() {} + virtual void adjust_timer(double delay) = 0; +}; + +// ---------------------------------------------------------------------------------------- +// netlist_setup_t +// ---------------------------------------------------------------------------------------- + +class netlist_setup_t +{ +public: + + struct net_input_setup_t { + public: + net_input_setup_t(net_input_t *inp, net_input_type type = NET_INP_TYPE_ACTIVE) + : m_inp(inp), m_type(type) {} + net_input_t *inp() { return m_inp; } + net_input_type type() { return m_type; } + private: + net_input_t *m_inp; + net_input_type m_type; + }; + + typedef tagmap_t tagmap_devices_t; + typedef tagmap_t tagmap_astring_t; + typedef tagmap_t tagmap_output_t; + typedef tagmap_t tagmap_input_t; + typedef tagmap_t tagmap_param_t; + + netlist_setup_t(netlist_base_t &netlist); + ~netlist_setup_t(); + + netlist_base_t &netlist() { return m_netlist; } + + net_dev_t *register_dev(net_dev_t *dev); + void remove_dev(const char *name); + + void register_output(const char *name, net_output_t *out); + void register_input(const char *name, net_input_t *inp, net_input_type type = NET_INP_TYPE_ACTIVE); + void register_alias(const char *alias, const char *out); + void register_param(const char *sname, net_param_t *param); + + void register_link(const char *sin, const char *sout); + + net_output_t *find_output(const char *outname_in); + net_param_t *find_param(const char *param_in); + + void register_callback(const char *devname, net_output_delegate delegate); + + void parse(char *buf); + + void resolve_inputs(void); + + /* not ideal, but needed for save_state */ + tagmap_output_t m_outputs; + + 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; + + void step_all_devices(); + net_output_t *find_output_exact(const char *outname_in); + const char *resolve_alias(const char *name) const; +}; + +// ---------------------------------------------------------------------------------------- +// netlist_base_t +// ---------------------------------------------------------------------------------------- + +class netlist_base_t +{ +public: + + netlist_base_t(bool sub_cycle_exact); + virtual ~netlist_base_t(); + + virtual netlist_base_timer_t *alloc_timer(net_dev_t *dev, INT32 timer_id) = 0; + + void set_clock_freq(int clockfreq); + void set_gatedelay(int gatedelay); + + ATTR_HOT inline void register_in_list(net_output_t *out, const UINT8 delay_ns) + { + m_output_list[m_sub_cycle_exact ? ((m_current + delay_ns / m_divisor) & m_netlist_mask) : 0].add(out); + } + + ATTR_HOT inline void register_in_list(net_output_t *out) + { + m_output_list[m_sub_cycle_exact ? (m_current & m_netlist_mask) : 0].add(out); + } + + ATTR_HOT inline void reset_list() + { + m_output_list[m_sub_cycle_exact ? m_current : 0].clear(); + } + + ATTR_COLD void reset_lists() + { + for (int i = 0; i <= m_netlist_mask; i++) + m_output_list[i].clear(); + } + + ATTR_HOT void process_list(void); + +protected: + UINT8 m_current; + UINT8 m_divisor; + UINT8 m_netlist_mask; + bool m_sub_cycle_exact; + net_list_t m_output_list[NET_LIST_SIZE]; + int m_gatedelay; + int m_clockfreq; + +private: + +}; + + +// ---------------------------------------------------------------------------------------- +// dev_callback +// ---------------------------------------------------------------------------------------- + +class netdev_callback : public net_dev_t +{ +public: + netdev_callback(netlist_setup_t *parent, const char *name) + : net_dev_t(parent, name) + { + register_input("IN", &m_in); + } + + void register_callback(net_output_delegate callback) + { + m_callback = callback; + } + + ATTR_HOT void update(); + +private: + net_input_t m_in; + net_output_delegate m_callback; +}; + +// ---------------------------------------------------------------------------------------- +// Inline implementations +// ---------------------------------------------------------------------------------------- + +ATTR_HOT inline void net_output_t::register_in_list(const UINT8 delay_ns) +{ + m_netlist->register_in_list(this, delay_ns); +} + +ATTR_HOT inline void net_output_t::register_in_list() +{ + m_netlist->register_in_list(this); +} + +// ---------------------------------------------------------------------------------------- +// net_dev class factory +// ---------------------------------------------------------------------------------------- + +class net_dev_t_base_factory +{ +public: + virtual ~net_dev_t_base_factory() {} + virtual net_dev_t *Create(netlist_setup_t *setup, const char *name) = 0; + + const char *name() { return m_name; } + const char *classname() { return m_classname; } +protected: + const char *m_name; /* device name */ + const char *m_classname; /* device class name */ +}; + +template +class net_dev_t_factory : public net_dev_t_base_factory +{ +public: + net_dev_t_factory(const char *name, const char *classname) { m_name = name; m_classname = classname; } + net_dev_t *Create(netlist_setup_t *setup, const char *name) + { + net_dev_t *r = global_alloc_clear(C(setup, name)); + return r; + } +}; + +net_dev_t *net_create_device_by_classname(const char *classname, netlist_setup_t *setup, const char *icname); +net_dev_t *net_create_device_by_name(const char *name, netlist_setup_t *setup, const char *icname); + +// ---------------------------------------------------------------------------------------- +// MAME glue classes +// ---------------------------------------------------------------------------------------- + +class netlist_timer_t : public netlist_base_timer_t +{ +public: + netlist_timer_t(device_t &parent, net_dev_t *dev, INT32 timer_id) + : netlist_base_timer_t() + { + m_param = timer_id; + m_timer = parent.machine().scheduler().timer_alloc(timer_expired_delegate(&netlist_timer_t::timer_cb, "netlist_timer_t::timer_cb", this), dev); + } + + virtual void adjust_timer(double delay) + { + m_timer->adjust(attotime::from_double(delay) ,m_param, attotime::never); + } + + void timer_cb(void *ptr, INT32 param) + { + net_dev_t *dev = (net_dev_t *) ptr; + dev->timer_cb(param); + } +private: + + INT32 m_param; + emu_timer *m_timer; +}; + +class netlist_t : public netlist_base_t +{ +public: + + netlist_t(device_t &parent, bool sub_cycle_exact) + : netlist_base_t(sub_cycle_exact), + m_parent(parent) + {} + virtual ~netlist_t() { }; + + inline running_machine &machine() { return m_parent.machine(); } + + virtual netlist_base_timer_t *alloc_timer(net_dev_t *dev, INT32 timer_id) + { + netlist_timer_t *ret = new netlist_timer_t(m_parent, dev, timer_id); + return ret; + } + + device_t &parent() { return m_parent; } + +private: + device_t &m_parent; +}; + +// ======================> netlist_mame_device + + +class netlist_mame_device : public device_t, + public device_execute_interface +{ +public: + + template + class output_finder; + class optional_output; + class required_output; + class optional_param; + class required_param; + class on_device_start; + + // construction/destruction + netlist_mame_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + static void static_set_subcycles(device_t &device, int subcycles); + static void static_set_constructor(device_t &device, void (*setup_func)(netlist_setup_t &)); + + netlist_setup_t &setup() { return *m_setup; } + netlist_t &netlist() { return *m_netlist; } + + //ATTR_HOT inline UINT64 Clocks() { return m_clockcnt; } + ATTR_HOT inline int SubCycles() const { return m_subcycles; } + + net_list_t m_device_start_list; + +protected: + // device-level overrides + virtual void device_config_complete(); + virtual void device_start(); + virtual void device_stop(); + virtual void device_reset(); + virtual void device_post_load(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const; + virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const; + + ATTR_HOT virtual void execute_run(); + + netlist_t *m_netlist; + net_output_t *m_clock_input; + + netlist_setup_t *m_setup; + +private: + + void step_one_clock(); + void save_state(); + + int m_clock; + int m_subcycles; + + void (*m_setup_func)(netlist_setup_t &); + + UINT32 dummy[8]; + + int m_icount; + int m_ss; + int m_clk; + + +}; + +// ======================> netlist_output_finder + +class netlist_mame_device::on_device_start +{ +public: + virtual bool OnDeviceStart() = 0; +}; + +// device finder template +template +class netlist_mame_device::output_finder : public device_t::object_finder_base<_NETClass>, + netlist_mame_device::on_device_start +{ +public: + // construction/destruction + output_finder(device_t &base, const char *tag, const char *output) + : object_finder_base<_NETClass>(base, tag), m_output(output) { } + + // finder + virtual bool findit() + { + device_t *device = this->m_base.subdevice(this->m_tag); + m_netlist = dynamic_cast(device); + if (device != NULL && m_netlist == NULL) + { + void mame_printf_warning(const char *format, ...) ATTR_PRINTF(1,2); + mame_printf_warning("Device '%s' found but is not netlist\n", this->m_tag); + } + m_netlist->m_device_start_list.add(this); + return this->report_missing(m_netlist != NULL, "device", _Required); + } + +protected: + netlist_mame_device *m_netlist; + const char *m_output; +}; + +// optional device finder +class netlist_mame_device::optional_output : public netlist_mame_device::output_finder +{ +public: + optional_output(device_t &base, const char *tag, const char *output) : output_finder(base, tag, output) { } + + virtual bool OnDeviceStart() + { + this->m_target = m_netlist->setup().find_output(m_output); + return this->report_missing(this->m_target != NULL, "output", false); + } + +}; + +// required devices are similar but throw an error if they are not found +class netlist_mame_device::required_output : public netlist_mame_device::output_finder +{ +public: + required_output(device_t &base, const char *tag, const char *output) : output_finder(base, tag, output) { } + + virtual bool OnDeviceStart() + { + this->m_target = m_netlist->setup().find_output(m_output); + return this->report_missing(this->m_target != NULL, "output", true); + } + +}; + +// optional device finder +class netlist_mame_device::optional_param : public netlist_mame_device::output_finder +{ +public: + optional_param(device_t &base, const char *tag, const char *output) : output_finder(base, tag, output) { } + + virtual bool OnDeviceStart() + { + this->m_target = m_netlist->setup().find_param(m_output); + return this->report_missing(this->m_target != NULL, "parameter", false); + } + +}; + +// required devices are similar but throw an error if they are not found +class netlist_mame_device::required_param : public netlist_mame_device::output_finder +{ +public: + required_param(device_t &base, const char *tag, const char *output) : output_finder(base, tag, output) { } + + virtual bool OnDeviceStart() + { + this->m_target = m_netlist->setup().find_param(m_output); + return this->report_missing(this->m_target != NULL, "output", true); + } +}; + +// device type definition +extern const device_type NETLIST; + +#endif