Analog input updates now send to queue. Reduces risk of stack overflows.

Fixed a bug which caused NAND astable multivibrator to oscillate. 
74123 improvements
This commit is contained in:
Couriersud 2014-05-15 00:03:27 +00:00
parent beb96a628d
commit fa60c8874d
9 changed files with 1564 additions and 30 deletions

1
.gitattributes vendored
View File

@ -368,6 +368,7 @@ nl_examples/74123_mstable.c svneol=native#text/plain
nl_examples/bjt.c svneol=native#text/plain
nl_examples/bjt_eb.c svneol=native#text/plain
nl_examples/bjt_eb_pnp.c svneol=native#text/plain
nl_examples/breakout.c svneol=native#text/plain
nl_examples/cd4066.c svneol=native#text/plain
nl_examples/msx_mixer_stage.c svneol=native#text/plain
nl_examples/ne555_astable.c svneol=native#text/plain

View File

@ -20,10 +20,10 @@ NETLIST_START(74123_mstable)
/* Wiring up the 74123 */
CLOCK(clk, 500)
CLOCK(clk, 50)
TTL_74123(mf)
RES(R, 1000)
RES(R, 10000)
CAP(C, 1e-6)
NET_C(GND, mf.GND)
@ -38,8 +38,8 @@ NETLIST_START(74123_mstable)
NET_C(mf.B, V5)
NET_C(mf.A, clk.Q)
//LOG(logC, C.2)
//LOG(logQ, mf.Q)
//LOG(logX, clk.Q)
LOG(logC, C.2)
LOG(logQ, mf.Q)
LOG(logX, clk.Q)
NETLIST_END()

1460
nl_examples/breakout.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -18,6 +18,19 @@
#define SOLVER_VERBOSE_OUT(x) do {} while (0)
//#define SOLVER_VERBOSE_OUT(x) printf x
ATTR_COLD netlist_matrix_solver_t::netlist_matrix_solver_t()
: m_owner(NULL)
{
}
ATTR_COLD netlist_matrix_solver_t::~netlist_matrix_solver_t()
{
#if NEW_INPUT
for (int i = 0; i < m_inps.count(); i++)
delete m_inps[i];
#endif
}
ATTR_COLD void netlist_matrix_solver_t::setup(netlist_net_t::list_t &nets, NETLIB_NAME(solver) &aowner)
{
m_owner = &aowner;
@ -66,10 +79,24 @@ ATTR_COLD void netlist_matrix_solver_t::setup(netlist_net_t::list_t &nets, NETLI
NL_VERBOSE_OUT(("Added terminal\n"));
break;
case netlist_terminal_t::INPUT:
if (!m_inps.contains(p))
m_inps.add(p);
NL_VERBOSE_OUT(("Added input\n"));
break;
{
#if NEW_INPUT
// FIXME: multiple outputs per net ...
netlist_analog_output_t *m = new netlist_analog_output_t();
m->init_object(*this, this->name() + "." + pstring::sprintf("m%d", m_inps.count()));
//register_output("m", *m);
m_inps.add(m);
m->m_proxied_net = &p->net();
m->net().register_con(*p);
// FIXME: repeated
m->net().rebuild_list();
#else
if (!m_inps.contains(p))
m_inps.add(p)
#endif
NL_VERBOSE_OUT(("Added input\n"));
}
break;
default:
owner().netlist().error("unhandled element found\n");
break;
@ -81,6 +108,18 @@ ATTR_COLD void netlist_matrix_solver_t::setup(netlist_net_t::list_t &nets, NETLI
ATTR_HOT void netlist_matrix_solver_t::update_inputs()
{
#if NEW_INPUT
// avoid recursive calls. Inputs are updated outside this call
for (netlist_analog_output_t * const *p = m_inps.first(); p != NULL; p = m_inps.next(p))
if ((*p)->m_proxied_net->m_last_Analog != (*p)->m_proxied_net->m_cur_Analog)
(*p)->set_Q((*p)->m_proxied_net->m_cur_Analog);
for (netlist_analog_output_t * const *p = m_inps.first(); p != NULL; p = m_inps.next(p))
{
if ((*p)->m_proxied_net->m_last_Analog != (*p)->m_proxied_net->m_cur_Analog)
(*p)->m_proxied_net->m_last_Analog = (*p)->m_proxied_net->m_cur_Analog;
}
#else
for (netlist_core_terminal_t * const *p = m_inps.first(); p != NULL; p = m_inps.next(p))
{
if ((*p)->net().m_last_Analog != (*p)->net().m_cur_Analog)
@ -93,6 +132,7 @@ ATTR_HOT void netlist_matrix_solver_t::update_inputs()
if ((*p)->net().m_last_Analog != (*p)->net().m_cur_Analog)
(*p)->net().m_last_Analog = (*p)->net().m_cur_Analog;
}
#endif
}
@ -156,14 +196,15 @@ ATTR_HOT bool netlist_matrix_solver_t::solve()
netlist_time now = owner().netlist().time();
netlist_time delta = now - m_last_step;
if (delta < netlist_time::from_nsec(1)) // always update capacitors
delta = netlist_time::from_nsec(1);
{
NL_VERBOSE_OUT(("Step!\n"));
/* update all terminals for new time step */
m_last_step = now;
step(delta);
}
// We are already up to date. Avoid oscillations.
if (delta < netlist_time::from_nsec(1))
return true;
NL_VERBOSE_OUT(("Step!\n"));
/* update all terminals for new time step */
m_last_step = now;
//printf("usecs: %f\n", delta.as_double()*1000000.0);
step(delta);
if (is_dynamic())
{
@ -832,11 +873,12 @@ ATTR_COLD void NETLIB_NAME(solver)::post_start()
ms->m_params.m_nr_loops = m_nr_loops.Value();
ms->m_params.m_nt_sync_delay = m_sync_delay.Value();
ms->setup(groups[i], *this);
register_sub(*ms, pstring::sprintf("Solver %d",m_mat_solvers.count()));
m_mat_solvers.add(ms);
ms->setup(groups[i], *this);
m_mat_solvers.add(ms);
netlist().log("Solver %s", ms->name().cstr());
netlist().log(" # %d ==> %d nets %s", i, groups[i].count(), (*(*groups[i].first())->m_core_terms.first())->name().cstr());

View File

@ -9,6 +9,8 @@
#include "../nl_setup.h"
#include "../nl_base.h"
#define NEW_INPUT (1)
// ----------------------------------------------------------------------------------------
// Macros
// ----------------------------------------------------------------------------------------
@ -40,8 +42,8 @@ public:
typedef netlist_list_t<netlist_matrix_solver_t *> list_t;
typedef netlist_core_device_t::list_t dev_list_t;
netlist_matrix_solver_t() : m_owner(NULL) {}
virtual ~netlist_matrix_solver_t() {}
ATTR_COLD netlist_matrix_solver_t();
ATTR_COLD virtual ~netlist_matrix_solver_t();
ATTR_COLD virtual void setup(netlist_net_t::list_t &nets, NETLIB_NAME(solver) &owner);
@ -75,7 +77,11 @@ protected:
netlist_net_t::list_t m_nets;
dev_list_t m_dynamic;
#if NEW_INPUT
netlist_list_t<netlist_analog_output_t *> m_inps;
#else
netlist_core_terminal_t::list_t m_inps;
#endif
dev_list_t m_steps;
netlist_time m_last_step;

View File

@ -6,7 +6,7 @@
#include "nld_74123.h"
#define R_OFF (1E20)
#define R_ON (1)
#define R_ON (m_RI.Value())
NETLIB_START(74123)
{
@ -27,20 +27,36 @@ NETLIB_START(74123)
register_subalias("C", m_RN.m_N);
register_subalias("RC", m_RN.m_P);
register_param("K", m_K, 0.4);
register_param("RI", m_RI, 400.0); // around 250 for HC series, 400 on LS/TTL, estimated from datasheets
connect(m_RN.m_P, m_RP.m_N);
connect(m_CV, m_RN.m_P);
save(NAME(m_last_trig));
save(NAME(m_state));
save(NAME(m_KP));
m_KP = 1.0 / (1.0 + exp(m_K.Value()));
}
NETLIB_UPDATE(74123)
{
// FIXME: CLR!
const netlist_sig_t m_trig = (INPLOGIC(m_A) ^ 1) & INPLOGIC(m_B) & INPLOGIC(m_CLRQ);
if (!m_last_trig && m_trig)
if (!INPLOGIC(m_CLRQ))
{
OUTLOGIC(m_Q, 0, NLTIME_FROM_NS(10));
OUTLOGIC(m_QQ, 1, NLTIME_FROM_NS(10));
/* quick charge until trigger */
/* FIXME: SGS datasheet shows quick charge to 5V,
* though schematics indicate quick charge to Vhigh only.
*/
m_RP.set_R(R_ON);
m_RN.set_R(R_OFF);
m_state = 2; //charging (quick)
}
else if (!m_last_trig && m_trig)
{
// FIXME: Timing!
OUTLOGIC(m_Q, 1, NLTIME_FROM_NS(10));
@ -54,7 +70,8 @@ NETLIB_UPDATE(74123)
if (m_state == 1)
{
if (INPANALOG(m_CV) < 1.3)
const double vLow = m_KP * TERMANALOG(m_RP.m_P);
if (INPANALOG(m_CV) < vLow)
{
m_RN.set_R(R_OFF);
m_state = 2; // charging
@ -62,8 +79,10 @@ NETLIB_UPDATE(74123)
}
else if (m_state == 2)
{
if (INPANALOG(m_CV) > 3.7)
const double vHigh = TERMANALOG(m_RP.m_P) * (1.0 - m_KP);
if (INPANALOG(m_CV) > vHigh)
{
m_RP.set_R(R_OFF);
OUTLOGIC(m_Q, 0, NLTIME_FROM_NS(10));
OUTLOGIC(m_QQ, 1, NLTIME_FROM_NS(10));
m_state = 0; // waiting

View File

@ -3,7 +3,7 @@
/*
* nld_74123.h
*
* 74123: PRECISION TIMERS
* 74123: Dual Retriggerable One-Shot with Clear and Complementary Outputs
*
* +--------------+
* A1 |1 ++ 16| VCC
@ -43,8 +43,12 @@ public:
netlist_analog_input_t m_CV;
netlist_sig_t m_last_trig;
netlist_sig_t m_last_trig;
UINT8 m_state;
double m_KP;
netlist_param_double_t m_K;
netlist_param_double_t m_RI;
);

View File

@ -841,7 +841,7 @@ ATTR_HOT void netlist_analog_output_t::set_Q(const double newQ)
if (newQ != net().m_new_Analog)
{
net().m_new_Analog = newQ;
net().push_to_queue(NLTIME_FROM_NS(0));
net().push_to_queue(NLTIME_FROM_NS(1));
}
}

View File

@ -723,6 +723,8 @@ public:
ATTR_HOT void set_Q(const double newQ);
netlist_net_t *m_proxied_net; // only for proxy nets in analog input logic
};
// ----------------------------------------------------------------------------------------