ATTR_COLD nl_double netlist_param_model_t::model_value(const pstring &entity, const nl_double defval) const { pstring tmp = this->Value(); // .model 1N914 D(Is=2.52n Rs=.568 N=1.752 Cjo=4p M=.4 tt=20n Iave=200m Vpk=75 mfg=OnSemi type=silicon) int p = tmp.ucase().find(entity.ucase() + "="); if (p>=0) { int pblank = tmp.find(" ", p); if (pblank < 0) pblank = tmp.len() + 1; tmp = tmp.substr(p, pblank - p); int pequal = tmp.find("=", 0); if (pequal < 0) netlist().error("parameter %s misformat in model %s temp %s\n", entity.cstr(), Value().cstr(), tmp.cstr()); tmp = tmp.substr(pequal+1); nl_double factor = NL_FCONST(1.0); switch (*(tmp.right(1).cstr())) { case 'm': factor = 1e-3; break; case 'u': factor = 1e-6; break; case 'n': factor = 1e-9; break; case 'p': factor = 1e-12; break; case 'f': factor = 1e-15; break; case 'a': factor = 1e-18; break; } if (factor != NL_FCONST(1.0)) tmp = tmp.left(tmp.len() - 1); return (nl_double) atof(tmp.cstr()) * factor; } else { netlist().log("Entity %s not found in model %s\n", entity.cstr(), tmp.cstr()); return defval; } }
ATTR_COLD analog_output_t::analog_output_t() : analog_t(OUTPUT), m_proxied_net(nullptr) { this->set_net(m_my_net); set_state(STATE_OUT); net().m_cur_Analog = NL_FCONST(0.99); }
void nld_d_to_a_proxy::reset() { m_Q.initial(0.0); m_last_state = -1; m_RV.do_reset(); m_is_timestep = m_RV.m_P.net().as_analog().solver()->is_timestep(); m_RV.set(NL_FCONST(1.0) / logic_family().m_R_low, logic_family().m_low_V, 0.0); }
ATTR_COLD analog_output_t::analog_output_t() : netlist_analog_t(OUTPUT), m_proxied_net(NULL) { this->set_net(m_my_net); set_state(STATE_OUT); net().as_analog().m_cur_Analog = NL_FCONST(0.99); }
netlist_time matrix_solver_t::compute_next_timestep(const double cur_ts) { nl_double new_solver_timestep = m_params.m_max_timestep; if (m_params.m_dynamic) { /* * FIXME: We should extend the logic to use either all nets or * only output nets. */ for (std::size_t k = 0, iN=m_terms.size(); k < iN; k++) { analog_net_t *n = m_nets[k]; terms_t *t = m_terms[k]; const nl_double DD_n = (n->Q_Analog() - t->m_last_V); const nl_double hn = cur_ts; nl_double DD2 = (DD_n / hn - t->m_DD_n_m_1 / t->m_h_n_m_1) / (hn + t->m_h_n_m_1); nl_double new_net_timestep; t->m_h_n_m_1 = hn; t->m_DD_n_m_1 = DD_n; if (std::fabs(DD2) > NL_FCONST(1e-60)) // avoid div-by-zero new_net_timestep = std::sqrt(m_params.m_lte / std::fabs(NL_FCONST(0.5)*DD2)); else new_net_timestep = m_params.m_max_timestep; if (new_net_timestep < new_solver_timestep) new_solver_timestep = new_net_timestep; t->m_last_V = n->Q_Analog(); } if (new_solver_timestep < m_params.m_min_timestep) new_solver_timestep = m_params.m_min_timestep; } //if (new_solver_timestep > 10.0 * hn) // new_solver_timestep = 10.0 * hn; /* * FIXME: Factor 2 below is important. Without, we get timing issues. This must be a bug elsewhere. */ return std::max(netlist_time::from_double(new_solver_timestep), netlist_time::quantum() * 2); }
analog_output_t::analog_output_t(core_device_t &dev, const pstring &aname) : analog_t(dev, aname, OUTPUT) , m_my_net(dev.netlist(), name() + ".net", this) { this->set_net(&m_my_net); set_state(STATE_OUT); net().m_cur_Analog = NL_FCONST(0.0); netlist().setup().register_term(*this); }
ATTR_COLD analog_output_t::analog_output_t(core_device_t &dev, const pstring &aname) : analog_t(OUTPUT), m_proxied_net(nullptr) { this->set_net(m_my_net); set_state(STATE_OUT); net().m_cur_Analog = NL_FCONST(0.99); analog_t::init_object(dev, aname); net().init_object(dev.netlist(), aname + ".net"); net().register_railterminal(*this); }
netlist_time matrix_solver_t::compute_next_timestep() { nl_double new_solver_timestep = m_params.m_max_timestep; if (m_params.m_dynamic) { /* * FIXME: We should extend the logic to use either all nets or * only output nets. */ for (unsigned k = 0, iN=m_terms.size(); k < iN; k++) { analog_net_t *n = m_nets[k]; terms_t *t = m_terms[k]; const nl_double DD_n = (n->Q_Analog() - t->m_last_V); const nl_double hn = current_timestep(); nl_double DD2 = (DD_n / hn - t->m_DD_n_m_1 / t->m_h_n_m_1) / (hn + t->m_h_n_m_1); nl_double new_net_timestep; t->m_h_n_m_1 = hn; t->m_DD_n_m_1 = DD_n; if (nl_math::abs(DD2) > NL_FCONST(1e-30)) // avoid div-by-zero new_net_timestep = nl_math::sqrt(m_params.m_lte / nl_math::abs(NL_FCONST(0.5)*DD2)); else new_net_timestep = m_params.m_max_timestep; if (new_net_timestep < new_solver_timestep) new_solver_timestep = new_net_timestep; t->m_last_V = n->Q_Analog(); } if (new_solver_timestep < m_params.m_min_timestep) new_solver_timestep = m_params.m_min_timestep; } //if (new_solver_timestep > 10.0 * hn) // new_solver_timestep = 10.0 * hn; return netlist_time::from_double(new_solver_timestep); }
void nld_d_to_a_proxy::reset() { // FIXME: Variable voltage double supply_V = logic_family().fixed_V(); if (supply_V == 0.0) supply_V = 5.0; //m_Q.initial(0.0); m_last_state = -1; m_RV.do_reset(); m_is_timestep = m_RV.m_P.net().solver()->has_timestep_devices(); m_RV.set(NL_FCONST(1.0) / logic_family().R_low(), logic_family().low_V(0.0, supply_V), 0.0); }
ATTR_HOT void nld_d_to_a_proxy::update() { const int state = INPLOGIC(m_I); if (state != m_last_state) { m_last_state = state; const nl_double R = state ? logic_family().m_R_high : logic_family().m_R_low; const nl_double V = state ? logic_family().m_high_V : logic_family().m_low_V; // We only need to update the net first if this is a time stepping net if (m_is_timestep) { m_RV.update_dev(); } m_RV.set(NL_FCONST(1.0) / R, V, 0.0); m_RV.m_P.schedule_after(NLTIME_FROM_NS(1)); } }
ATTR_COLD void netlist_analog_output_t::initial(const nl_double val) { // FIXME: Really necessary? net().as_analog().m_cur_Analog = val * NL_FCONST(0.99); }
ATTR_COLD void NETLIB_NAME(solver)::post_start() { pvector_t<analog_net_t::list_t> groups; const bool use_specific = true; m_params.m_pivot = m_pivot.Value(); m_params.m_accuracy = m_accuracy.Value(); m_params.m_gs_loops = m_gs_loops.Value(); m_params.m_nr_loops = m_nr_loops.Value(); m_params.m_nt_sync_delay = netlist_time::from_double(m_sync_delay.Value()); m_params.m_lte = m_lte.Value(); m_params.m_sor = m_sor.Value(); m_params.m_min_timestep = m_min_timestep.Value(); m_params.m_dynamic = (m_dynamic.Value() == 1 ? true : false); m_params.m_max_timestep = netlist_time::from_hz(m_freq.Value()).as_double(); if (m_params.m_dynamic) { m_params.m_max_timestep *= NL_FCONST(1000.0); } else { m_params.m_min_timestep = m_params.m_max_timestep; } // Override log statistics pstring p = nl_util::environment("NL_STATS"); if (p != "") m_params.m_log_stats = (bool) p.as_long(); else m_params.m_log_stats = (bool) m_log_stats.Value(); netlist().log().verbose("Scanning net groups ..."); // determine net groups for (auto & net : netlist().m_nets) { netlist().log().debug("processing {1}\n", net->name()); if (!net->isRailNet()) { netlist().log().debug(" ==> not a rail net\n"); analog_net_t *n = &net->as_analog(); if (!n->already_processed(groups)) { groups.push_back(analog_net_t::list_t()); n->process_net(groups); } } } // setup the solvers netlist().log().verbose("Found {1} net groups in {2} nets\n", groups.size(), netlist().m_nets.size()); for (auto & grp : groups) { matrix_solver_t *ms; std::size_t net_count = grp.size(); switch (net_count) { case 1: ms = create_solver<1,1>(1, use_specific); break; case 2: ms = create_solver<2,2>(2, use_specific); break; case 3: ms = create_solver<3,3>(3, use_specific); break; case 4: ms = create_solver<4,4>(4, use_specific); break; case 5: ms = create_solver<5,5>(5, use_specific); break; case 6: ms = create_solver<6,6>(6, use_specific); break; case 7: ms = create_solver<7,7>(7, use_specific); break; case 8: ms = create_solver<8,8>(8, use_specific); break; case 10: ms = create_solver<10,10>(10, use_specific); break; case 11: ms = create_solver<11,11>(11, use_specific); break; case 12: ms = create_solver<12,12>(12, use_specific); break; case 15: ms = create_solver<15,15>(15, use_specific); break; case 31: ms = create_solver<31,31>(31, use_specific); break; case 49: ms = create_solver<49,49>(49, use_specific); break; #if 0 case 87: ms = create_solver<87,87>(87, use_specific); break; #endif default: netlist().log().warning("No specific solver found for netlist of size {1}", (unsigned) net_count); if (net_count <= 16) { ms = create_solver<0,16>(net_count, use_specific); } else if (net_count <= 32) { ms = create_solver<0,32>(net_count, use_specific); } else if (net_count <= 64) { ms = create_solver<0,64>(net_count, use_specific); } else if (net_count <= 128) { ms = create_solver<0,128>(net_count, use_specific); } else { netlist().log().fatal("Encountered netgroup with > 128 nets"); ms = nullptr; /* tease compilers */ } break; } register_sub(*ms); ms->setup(grp); m_mat_solvers.push_back(ms); netlist().log().verbose("Solver {1}", ms->name()); netlist().log().verbose(" ==> {2} nets", grp.size()); netlist().log().verbose(" has {1} elements", ms->is_dynamic() ? "dynamic" : "no dynamic"); netlist().log().verbose(" has {1} elements", ms->is_timestep() ? "timestep" : "no timestep"); for (net_t *n : grp) { netlist().log().verbose("Net {1}", n->name()); for (const core_terminal_t *pcore : n->m_core_terms) { netlist().log().verbose(" {1}", pcore->name()); } } } }
ATTR_COLD void NETLIB_NAME(solver)::post_start() { analog_net_t::list_t groups[256]; int cur_group = -1; const bool use_specific = true; m_params.m_accuracy = m_accuracy.Value(); m_params.m_gs_loops = m_gs_loops.Value(); m_params.m_nr_loops = m_nr_loops.Value(); m_params.m_nt_sync_delay = m_sync_delay.Value(); m_params.m_lte = m_lte.Value(); m_params.m_sor = m_sor.Value(); m_params.m_min_timestep = m_min_timestep.Value(); m_params.m_dynamic = (m_dynamic.Value() == 1 ? true : false); m_params.m_max_timestep = netlist_time::from_hz(m_freq.Value()).as_double(); if (m_params.m_dynamic) { m_params.m_max_timestep *= NL_FCONST(1000.0); } else { m_params.m_min_timestep = m_params.m_max_timestep; } // Override log statistics pstring p = nl_util::environment("NL_STATS"); if (p != "") m_params.m_log_stats = (bool) p.as_long(); else m_params.m_log_stats = (bool) m_log_stats.Value(); netlist().log("Scanning net groups ..."); // determine net groups for (std::size_t i=0; i<netlist().m_nets.size(); i++) { SOLVER_VERBOSE_OUT(("processing %s\n", netlist().m_nets[i]->name().cstr())); if (!netlist().m_nets[i]->isRailNet()) { SOLVER_VERBOSE_OUT((" ==> not a rail net\n")); analog_net_t *n = &netlist().m_nets[i]->as_analog(); if (!n->already_processed(groups, cur_group)) { cur_group++; n->process_net(groups, cur_group); } } } // setup the solvers netlist().log("Found %d net groups in %" SIZETFMT " nets\n", cur_group + 1, SIZET_PRINTF(netlist().m_nets.size())); for (int i = 0; i <= cur_group; i++) { matrix_solver_t *ms; std::size_t net_count = groups[i].size(); switch (net_count) { case 1: ms = create_solver<1,1>(1, use_specific); break; case 2: ms = create_solver<2,2>(2, use_specific); break; case 3: ms = create_solver<3,3>(3, use_specific); break; case 4: ms = create_solver<4,4>(4, use_specific); break; case 5: ms = create_solver<5,5>(5, use_specific); break; case 6: ms = create_solver<6,6>(6, use_specific); break; case 7: ms = create_solver<7,7>(7, use_specific); break; case 8: ms = create_solver<8,8>(8, use_specific); break; case 12: ms = create_solver<12,12>(12, use_specific); break; case 87: ms = create_solver<87,87>(87, use_specific); break; default: if (net_count <= 16) { ms = create_solver<0,16>(net_count, use_specific); } else if (net_count <= 32) { ms = create_solver<0,32>(net_count, use_specific); } else if (net_count <= 64) { ms = create_solver<0,64>(net_count, use_specific); } else if (net_count <= 128) { ms = create_solver<0,128>(net_count, use_specific); } else { netlist().error("Encountered netgroup with > 128 nets"); ms = NULL; /* tease compilers */ } break; } register_sub(pstring::sprintf("Solver_%" SIZETFMT,SIZET_PRINTF(m_mat_solvers.size())), *ms); ms->vsetup(groups[i]); m_mat_solvers.add(ms); netlist().log("Solver %s", ms->name().cstr()); netlist().log(" # %d ==> %" SIZETFMT " nets", i, SIZET_PRINTF(groups[i].size())); //, (*(*groups[i].first())->m_core_terms.first())->name().cstr()); netlist().log(" has %s elements", ms->is_dynamic() ? "dynamic" : "no dynamic"); netlist().log(" has %s elements", ms->is_timestep() ? "timestep" : "no timestep"); for (std::size_t j=0; j<groups[i].size(); j++) { netlist().log("Net %" SIZETFMT ": %s", SIZET_PRINTF(j), groups[i][j]->name().cstr()); net_t *n = groups[i][j]; for (std::size_t k = 0; k < n->m_core_terms.size(); k++) { const core_terminal_t *p = n->m_core_terms[k]; netlist().log(" %s", p->name().cstr()); } } } }