Fixed a nasty issue around convergence by defaulting to Gaussian elemination for 5x5 and 6x6 matrices. This prevented pong from starting.

In addition, removed a number of hacks around start-up conditions. All nets are now defaulted to "0" at startup. Much cleaner.
Added a 74LS629 device which yet needs to be enabled.
This commit is contained in:
Couriersud 2014-01-31 20:41:32 +00:00
parent 1bf2b1bde7
commit b04c5e54b9
19 changed files with 392 additions and 36 deletions

3
.gitattributes vendored
View File

@ -2195,6 +2195,8 @@ src/emu/netlist/devices/nld_7490.c svneol=native#text/plain
src/emu/netlist/devices/nld_7490.h svneol=native#text/plain
src/emu/netlist/devices/nld_7493.c svneol=native#text/plain
src/emu/netlist/devices/nld_7493.h svneol=native#text/plain
src/emu/netlist/devices/nld_74ls629.c svneol=native#text/plain
src/emu/netlist/devices/nld_74ls629.h svneol=native#text/plain
src/emu/netlist/devices/nld_9316.c svneol=native#text/plain
src/emu/netlist/devices/nld_9316.h svneol=native#text/plain
src/emu/netlist/devices/nld_legacy.c svneol=native#text/plain
@ -2210,6 +2212,7 @@ 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_dice_compat.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

View File

@ -770,6 +770,16 @@ ATTR_COLD void NETLIB_NAME(solver)::post_start()
ms = new netlist_matrix_solver_direct_t<4,4>();
//ms = new netlist_matrix_solver_gauss_seidel_t<4,4>();
break;
#if 1
case 5:
ms = new netlist_matrix_solver_direct_t<5,5>();
//ms = new netlist_matrix_solver_gauss_seidel_t<4,4>();
break;
case 6:
ms = new netlist_matrix_solver_direct_t<6,6>();
//ms = new netlist_matrix_solver_gauss_seidel_t<4,4>();
break;
#endif
default:
//ms = new netlist_matrix_solver_direct_t<0,16>();
ms = new netlist_matrix_solver_gauss_seidel_t<0,16>();

View File

@ -34,10 +34,6 @@ NETLIB_RESET(switch2)
}
NETLIB_UPDATE(switch2)
{
}
NETLIB_UPDATE_PARAM(switch2)
{
if (m_POS.Value() == 0)
{
@ -53,3 +49,8 @@ NETLIB_UPDATE_PARAM(switch2)
m_R[0].update_dev();
m_R[1].update_dev();
}
NETLIB_UPDATE_PARAM(switch2)
{
update();
}

View File

@ -110,6 +110,7 @@ void netlist_factory_t::initialize()
ENTRY(74107, TTL_74107, "+CLK,J,K,CLRQ")
ENTRY(74107A, TTL_74107A, "+CLK,J,K,CLRQ")
ENTRY(74153, TTL_74153, "+C0,C1,C2,C3,A,B,G")
//ENTRY(SN74LS629, SN74LS629, "CAP")
ENTRY(9316, TTL_9316, "+CLK,ENP,ENT,CLRQ,LOADQ,A,B,C,D")
ENTRY(NE555, NE555, "-")
ENTRY(7400_dip, TTL_7400_DIP, "-")

View File

@ -71,6 +71,7 @@
#include "nld_7493.h"
#include "nld_74107.h"
#include "nld_74153.h"
//#include "nld_74ls629.h"
#include "nld_9316.h"
#include "nld_ne555.h"

View File

@ -13,7 +13,6 @@ NETLIB_START(7404)
NETLIB_RESET(7404)
{
m_Q.initial(1);
}
NETLIB_UPDATE(7404)

View File

@ -19,8 +19,6 @@ NETLIB_START(74107Asub)
NETLIB_RESET(74107Asub)
{
m_clk.set_state(netlist_input_t::STATE_INP_HL);
m_Q.initial(0);
m_QQ.initial(1);
m_Q1 = 0;
m_Q2 = 0;

View File

@ -77,8 +77,6 @@ NETLIB_RESET(7474sub)
m_CLK.set_state(netlist_input_t::STATE_INP_LH);
m_nextD = 0;
m_Q.initial(1);
m_QQ.initial(0);
}
NETLIB_START(7474_dip)

View File

@ -0,0 +1,191 @@
/*
* nld_SN74LS629.c
*
*/
/*
* The 74LS624 series are constant current based VCOs. The Freq Control voltage
* modulates the current source. The current is created from Rext, which is
* internally fixed at 600 ohms for all devices except the 74LS628 which has
* external connections. The current source linearly discharges the cap voltage.
* The cap starts with 0V charge across it. One side is connected to a fixed voltage
* bias circuit. The other side is charged negatively from the current source until
* a certain low threshold is reached. Once this threshold is reached, the output
* toggles state and the pins on the cap reverse in respect to the charge/bias hookup.
* This starts the one side of the cap to be at bias, and the other side of the cap is
* now at bias + the charge on the cap which is bias - threshold.
* Y = 0; CX1 = bias; CX2 = charge
* Y = 1; CX1 = charge; CX2 = bias
* The Range voltage adjusts the threshold voltage. The higher the Range voltage,
* the lower the threshold voltage, the longer the cap can charge, the lower the frequency.
*
* In a perfect world it would work like this:
* The current is based on the mysterious Rext mentioned in the data sheet.
* I = (VfreqControl * 20k/90k) / Rext
* where Rext = 600 ohms or external Rext on a 74LS628
* The Freq Control has an input impedance of approximately 90k, so any input resistance
* connected to the Freq Control pin works as a voltage divider.
* I = (VfreqControl * 20k/(90k + RfreqControlIn)) / Rext
* That gives us a change in voltage on the cap of
* dV = I / sampleRate / C_inFarads
*
* Unfortunately the chip does not behave linearly do to internal interactions,
* so I have just worked out the formula (using zunzun.com) of FreqControl and
* range to frequency out for a fixed cap value of 0.1uf. Other cap values can just
* scale from that. From the freq, we calculate the time of 1/2 cycle using 1/Freq/2.
* Then just use that to toggle a waveform.
*/
#include "nld_74ls629.h"
#include "../nl_setup.h"
NETLIB_START(SN74LS629clk)
{
register_input("FB", m_FB);
register_output("Y", m_Y);
connect(m_FB, m_Y);
reset();
save(NAME(m_enableq));
save(NAME(m_inc));
}
NETLIB_RESET(SN74LS629clk)
{
m_enableq = 0;
m_inc = netlist_time::zero;
}
NETLIB_UPDATE(SN74LS629clk)
{
if (!m_enableq)
{
OUTLOGIC(m_Y, !m_Y.net().new_Q(), m_inc);
}
else
{
OUTLOGIC(m_Y, 1, m_inc);
}
}
NETLIB_START(SN74LS629)
{
register_sub(m_clock, "OSC");
register_sub(m_R_FC, "R_FC");
register_sub(m_R_RNG, "R_RNG");
m_R_FC.set_R(90000.0);
m_R_RNG.set_R(90000.0);
register_input("ENQ", m_ENQ);
register_input("RNG", m_RNG);
register_input("FC", m_FC);
register_subalias("GND", m_R_FC.m_N);
connect(m_FC, m_R_FC.m_P);
connect(m_RNG, m_R_RNG.m_P);
connect(m_R_FC.m_N, m_R_RNG.m_N);
register_subalias("Y", m_clock.m_Y);
register_param("CAP", m_CAP, 1e-6);
}
NETLIB_RESET(SN74LS629)
{
m_clock.reset();
}
NETLIB_UPDATE(SN74LS629)
{
{
// recompute
double freq;
double v_freq_2, v_freq_3, v_freq_4;
double v_freq = INPANALOG(m_FC);
double v_rng = INPANALOG(m_RNG);
/* coefficients */
const double k1 = 1.9904769024796283E+03;
const double k2 = 1.2070059213983407E+03;
const double k3 = 1.3266985579561108E+03;
const double k4 = -1.5500979825922698E+02;
const double k5 = 2.8184536266938172E+00;
const double k6 = -2.3503421582744556E+02;
const double k7 = -3.3836786704527788E+02;
const double k8 = -1.3569136703258670E+02;
const double k9 = 2.9914575453819188E+00;
const double k10 = 1.6855569086173170E+00;
/* scale due to input resistance */
/* Polyfunctional3D_model created by zunzun.com using sum of squared absolute error */
v_freq_2 = v_freq * v_freq;
v_freq_3 = v_freq_2 * v_freq;
v_freq_4 = v_freq_3 * v_freq;
freq = k1;
freq += k2 * v_freq;
freq += k3 * v_freq_2;
freq += k4 * v_freq_3;
freq += k5 * v_freq_4;
freq += k6 * v_rng;
freq += k7 * v_rng * v_freq;
freq += k8 * v_rng * v_freq_2;
freq += k9 * v_rng * v_freq_3;
freq += k10 * v_rng * v_freq_4;
freq *= 0.1e-6 / m_CAP.Value();
// FIXME: we need a possibility to remove entries from queue ...
// or an exact model ...
m_clock.m_inc = netlist_time::from_double(0.5 / freq);
//m_clock.update();
}
if (!m_clock.m_enableq && INPLOGIC(m_ENQ))
{
m_clock.m_enableq = 1;
OUTLOGIC(m_clock.m_Y, !m_clock.m_Y.net().last_Q(), netlist_time::from_nsec(1));
}
else if (m_clock.m_enableq && !INPLOGIC(m_ENQ))
{
m_clock.m_enableq = 0;
OUTLOGIC(m_clock.m_Y, !m_clock.m_Y.net().last_Q(), netlist_time::from_nsec(1));
}
}
NETLIB_UPDATE_PARAM(SN74LS629)
{
//printf("updating %s to %f\n", name().cstr(), m_R.Value());
update_dev();
//m_clock.update_dev();
}
#if 0
NETLIB_START(SN74LS629_dip)
{
NETLIB_NAME(SN74LS629)::start();
register_subalias("1", m_R3.m_N); // Pin 1
register_subalias("2", m_TRIG); // Pin 2
register_subalias("3", m_OUT); // Pin 3
register_subalias("4", m_RESET); // Pin 4
register_subalias("5", m_R1.m_N); // Pin 5
register_subalias("6", m_THRES); // Pin 6
register_subalias("7", m_RDIS.m_P); // Pin 7
register_subalias("8", m_R1.m_P); // Pin 8
}
NETLIB_UPDATE(SN74LS629_dip)
{
NETLIB_NAME(SN74LS629)::update();
}
NETLIB_RESET(SN74LS629_dip)
{
NETLIB_NAME(SN74LS629)::reset();
}
#endif

View File

@ -0,0 +1,65 @@
// license:GPL-2.0+
// copyright-holders:Couriersud
/*
* nld_74LS629.h
*
* SN74LS629: VOLTAGE-CONTROLLED OSCILLATORS
*
* +--------------+
* 2FC |1 ++ 14| VCC
* 1FC |2 13| QSC VCC
* 1RNG |3 12| 2RNG
* 1CX1 |4 74LS629 11| 2CX1
* 1CX2 |5 10| 2CX2
* 1ENQ |6 11| 2ENQ
* 1Y |7 10| 2Y
* OSC GND |8 9| GND
* +--------------+
*
* Naming conventions follow Texas Instruments datasheet
*
* NOTE: The CX1 and CX2 pins are not connected!
* The capacitor value has to be specified as a parameter.
* There are more comments on the challenges of emulating this
* chip in the *.c file
*
*/
#ifndef NLD_74LS629_H_
#define NLD_74LS629_H_
#include "../nl_base.h"
#include "../analog/nld_twoterm.h"
#define SN74LS629(_name, _cap) \
NET_REGISTER_DEV(SN74LS629, _name) \
NETDEV_PARAMI(_name, CAP, _cap)
NETLIB_SUBDEVICE(SN74LS629clk,
netlist_logic_input_t m_FB;
netlist_logic_output_t m_Y;
netlist_time m_inc;
netlist_sig_t m_enableq;
);
NETLIB_DEVICE_WITH_PARAMS(SN74LS629,
NETLIB_NAME(SN74LS629clk) m_clock;
NETLIB_NAME(R_base) m_R_FC;
NETLIB_NAME(R_base) m_R_RNG;
netlist_logic_input_t m_ENQ;
netlist_analog_input_t m_RNG;
netlist_analog_input_t m_FC;
netlist_param_double_t m_CAP;
);
#define SN74LS629_DIP(_name) \
NET_REGISTER_DEV(SN74LS629_dip, _name)
NETLIB_DEVICE_DERIVED(SN74LS629_dip, SN74LS629,
);
#endif /* NLD_74LS629_H_ */

View File

@ -16,8 +16,8 @@ NETLIB_START(nicRSFF)
NETLIB_RESET(nicRSFF)
{
m_Q.initial(0);
m_QQ.initial(1);
// m_Q.initial(0);
// m_QQ.initial(1);
}
NETLIB_UPDATE(nicRSFF)

View File

@ -47,7 +47,6 @@ public:
ATTR_COLD void reset()
{
m_Q.initial(1);
m_active = 1;
}
@ -100,7 +99,6 @@ public:
ATTR_COLD void reset()
{
m_Q.initial(1);
m_active = 1;
}
@ -173,7 +171,6 @@ public:
ATTR_COLD void reset()
{
m_Q.initial(1);
m_active = 1;
}

View File

@ -51,12 +51,15 @@ NETLIB_RESET(ttl_input)
NETLIB_UPDATE(ttl_input)
{
OUTLOGIC(m_Q, m_IN.Value() & 1, NLTIME_IMMEDIATE);
//m_Q.net().m_new.Q = !(m_IN.Value() & 1);
//OUTLOGIC(m_Q, m_IN.Value() & 1, NLTIME_IMMEDIATE);
OUTLOGIC(m_Q, m_IN.Value() & 1, netlist_time::from_nsec(1));
}
NETLIB_UPDATE_PARAM(ttl_input)
{
OUTLOGIC(m_Q, m_IN.Value() & 1, NLTIME_IMMEDIATE);
//m_Q.net().m_new.Q = !(m_IN.Value() & 1);
//OUTLOGIC(m_Q, m_IN.Value() & 1, NLTIME_IMMEDIATE);
}
// ----------------------------------------------------------------------------------------
@ -80,5 +83,5 @@ NETLIB_UPDATE(analog_input)
NETLIB_UPDATE_PARAM(analog_input)
{
OUTANALOG(m_Q, m_IN.Value(), NLTIME_IMMEDIATE);
//OUTANALOG(m_Q, m_IN.Value(), NLTIME_IMMEDIATE);
}

View File

@ -98,7 +98,7 @@ protected:
ATTR_COLD void reset()
{
m_Q.initial(0.001); // Make sure update outputs something
//m_Q.initial(0.001); // Make sure update outputs something
}
ATTR_HOT ATTR_ALIGN void update()
@ -140,7 +140,6 @@ protected:
ATTR_COLD void reset()
{
m_Q.initial(1);
}
ATTR_HOT ATTR_ALIGN void update()
@ -204,7 +203,7 @@ protected:
ATTR_COLD void reset()
{
m_Q.initial(0);
//m_Q.initial(0);
}
ATTR_COLD virtual netlist_core_terminal_t &out()
@ -240,16 +239,17 @@ protected:
register_output("_Q", m_Q);
register_subalias("Q", m_R.m_N);
connect(m_Q, m_R.m_P);
connect(m_R.m_P, m_Q);
m_Q.initial(0);
m_R.set_R(m_family_desc->m_R_low);
//m_Q.initial(m_family_desc->m_low_V);
//m_R.set_R(m_family_desc->m_R_low);
}
ATTR_COLD void reset()
{
m_Q.initial(0);
m_R.set_R(m_family_desc->m_R_low);
//m_Q.initial(m_family_desc->m_low_V);
//m_R.set_R(m_family_desc->m_R_low);
m_R.do_reset();
}
ATTR_COLD virtual netlist_core_terminal_t &out()
@ -259,8 +259,11 @@ protected:
ATTR_HOT ATTR_ALIGN void update()
{
m_R.set_R(INPLOGIC(m_I) ? m_family_desc->m_R_high : m_family_desc->m_R_low);
OUTANALOG(m_Q, INPLOGIC(m_I) ? m_family_desc->m_high_V : m_family_desc->m_low_V, NLTIME_FROM_NS(1));
double R = INPLOGIC(m_I) ? m_family_desc->m_R_high : m_family_desc->m_R_low;
double V = INPLOGIC(m_I) ? m_family_desc->m_high_V : m_family_desc->m_low_V;
//printf("%f %f\n", R, V);
m_R.set_R(R);
OUTANALOG(m_Q, V, NLTIME_FROM_NS(0));
}
private:

View File

@ -50,6 +50,7 @@ NETLISTOBJS+= \
$(NETLISTOBJ)/devices/nld_7493.o \
$(NETLISTOBJ)/devices/nld_74107.o \
$(NETLISTOBJ)/devices/nld_74153.o \
$(NETLISTOBJ)/devices/nld_74ls629.o \
$(NETLISTOBJ)/devices/nld_9316.o \
$(NETLISTOBJ)/devices/nld_ne555.o \
$(NETLISTOBJ)/devices/nld_legacy.o \

View File

@ -16,9 +16,9 @@ netlist_logic_family_desc_t netlist_family_ttl =
0.8, // m_low_thresh_V
2.0, // m_high_thresh_V
0.3, // m_low_V - these depend on sinked/sourced current. Values should be suitable for typical applications.
3.4, // m_high_V
10.0, // m_g_low;
130.0, //130.0, // m_g_high;
3.7, // m_high_V
1.0, // m_R_low;
130.0, // m_R_high;
};
// ----------------------------------------------------------------------------------------
@ -435,15 +435,16 @@ ATTR_COLD netlist_net_t::netlist_net_t(const type_t atype, const family_t afamil
, m_in_queue(2)
, m_railterminal(NULL)
{
m_last.Analog = -123456789.0; // set to something we will never hit.
//m_last.Analog = -123456789.0; // set to something we will never hit.
m_last.Analog = 0.0; // set to something we will never hit.
m_new.Analog = 0.0;
m_cur.Analog = 0.0;
};
ATTR_COLD void netlist_net_t::reset()
{
m_last.Analog = -123456789.0; // set to something we will never hit.
m_new.Analog = 0.0;
//m_last.Analog = -123456789.0; // set to something we will never hit.
m_last.Analog = 0.0; // set to something we will never hit.
m_cur.Analog = 0.0;
m_last.Q = 0; // set to something we will never hit.
m_new.Q = 0;
@ -632,7 +633,7 @@ ATTR_COLD void netlist_logic_output_t::initial(const netlist_sig_t val)
{
net().m_cur.Q = val;
net().m_new.Q = val;
net().m_last.Q = !val;
net().m_last.Q = val;
}
// ----------------------------------------------------------------------------------------

View File

@ -0,0 +1,79 @@
// license:MAME,GPL-2.0+
// copyright-holders:couriersud
/*
* nl_dice_compat.h
*
*/
#ifndef NL_DICE_COMPAT_H_
#define NL_DICE_COMPAT_H_
/* --------------------------------------------------------------------
* Compatibility macros for DICE netlists ...
* -------------------------------------------------------------------- */
//#define CHIP(_n, _t) netlist.register_dev(NET_NEW(_t ## _dip), _n);
#define CHIP(_n, _t) netlist.register_dev( new nld_ ## _t ## _dip(), _n);
#define CONNECTION( a... ) CONNECTIONX( a )
#define CONNECTIONX(_a, _b, _c, _d) netlist.register_link(_a "." # _b, _c "." # _d);
#define NET_CSTR(_a, _b) netlist.register_link( _a, _b);
#define CIRCUIT_LAYOUT(x) NETLIST_START(x)
#define CIRCUIT_LAYOUT_END NETLIST_END()
#define K_OHM(x) ((x) * 1000.0)
#define U_FARAD(x) ((x) * 1.0e-6)
struct Mono555Desc
{
public:
double r, c;
Mono555Desc(double res, double cap) : r(res), c(cap) { }
};
struct SeriesRCDesc
{
public:
double r, c;
SeriesRCDesc(double res, double cap) : r(res), c(cap) { }
};
#define CHIP_555_Mono(_name, _pdesc) \
CHIP(# _name, NE555) \
NET_C(_name.6, _name.7) \
RES(_name ## _R, (_pdesc)->r) \
CAP(_name ## _C, (_pdesc)->c) \
NET_C(_name.6, _name ## _R.1) \
NET_C(_name.6, _name ## _C.1) \
NET_C(_name ## _R.2, V5) \
NET_CSTR(# _name "_C.2", "GND") \
NET_C(_name.8, V5) \
NET_CSTR(# _name ".1", "GND")
#define CHIP_SERIES_RC(_name, _pdesc) \
RES(_name ## _R, (_pdesc)->r) \
CAP(_name ## _C, (_pdesc)->c) \
NET_C(_name ## _R.1, _name ## _C.2) \
ALIAS(_name.3, _name ## _R.1) \
ALIAS(_name.2, _name ## _R.2) \
ALIAS(_name.1, _name ## _C.1)
#define CHIP_INPUT(_name) \
SWITCH2(_name ## _SW) \
NET_C(_name ## _SW.2, V5) \
NET_CSTR(# _name "_SW.1", "GND") \
ALIAS(_name.1, _name ## _SW.Q)
#define CHIP_LATCH(_name) \
NETDEV_RSFF(_name) \
ALIAS(_name.1, _name.S) \
ALIAS(_name.2, _name.R) \
ALIAS(_name.3, _name.QQ)
#endif /* NL_DICE_COMPAT_H_ */

View File

@ -353,6 +353,7 @@ nld_base_d_to_a_proxy *netlist_setup_t::get_d_a_proxy(netlist_output_t &out)
{
assert(out.isFamily(netlist_terminal_t::LOGIC));
//printf("proxy for %s\n", out.name().cstr());;
netlist_logic_output_t &out_cast = dynamic_cast<netlist_logic_output_t &>(out);
nld_base_d_to_a_proxy *proxy = out_cast.get_proxy();
@ -366,6 +367,7 @@ nld_base_d_to_a_proxy *netlist_setup_t::get_d_a_proxy(netlist_output_t &out)
proxy->init(netlist(), x);
register_dev(proxy, x);
#if 1
/* connect all existing terminals to new net */
netlist_core_terminal_t *p = out.net().m_head;
@ -378,6 +380,7 @@ nld_base_d_to_a_proxy *netlist_setup_t::get_d_a_proxy(netlist_output_t &out)
}
out.net().m_head = NULL; // clear the list
out.net().m_num_cons = 0;
#endif
out.net().register_con(proxy->m_I);
out_cast.set_proxy(proxy);

View File

@ -63,7 +63,7 @@ fixedfreq_interface fixedfreq_mode_pong = {
H_TOTAL-67,H_TOTAL-40,H_TOTAL-8,H_TOTAL,
V_TOTAL-22,V_TOTAL-19,V_TOTAL-12,V_TOTAL,
1, /* non-interlaced */
0.30
0.31
};
fixedfreq_interface fixedfreq_mode_pongX2 = {
@ -71,7 +71,7 @@ fixedfreq_interface fixedfreq_mode_pongX2 = {
(H_TOTAL-67) * 2, (H_TOTAL-40) * 2, (H_TOTAL-8) * 2, (H_TOTAL) * 2,
V_TOTAL-22,V_TOTAL-19,V_TOTAL-16,V_TOTAL,
1, /* non-interlaced */
0.30
0.31
};
enum input_changed_enum
@ -571,6 +571,7 @@ static NETLIST_START(pong_schematics)
PARAM(sw1a.POS, 0)
NET_C(sw1a.1, high)
//NET_C(sw1a.1, V5)
NET_C(sw1a.2, ic_c7.QC)
TTL_7410_NAND(ic_d8a, ic_c7.QA, sw1a.Q, ic_c8a.Q) // would be nand2 for 11 instead of 15 points, need a switch dev!
@ -590,6 +591,7 @@ static NETLIST_START(pong_schematics)
PARAM(sw1b.POS, 0)
NET_C(sw1b.1, high)
//NET_C(sw1b.1, V5)
NET_C(sw1b.2, ic_d7.QC)