trunk/src/emu/netlist/nl_lists.h
| r26894 | r26895 | |
| 20 | 20 | { |
| 21 | 21 | public: |
| 22 | 22 | |
| 23 | | struct entry_t { |
| 23 | struct entry_t |
| 24 | { |
| 25 | friend class netlist_list_t; |
| 26 | public: |
| 24 | 27 | // keep compatibility with tagmap |
| 25 | | _ListClass object() { return m_obj; } |
| 26 | | |
| 28 | ATTR_HOT inline _ListClass object() { return m_obj; } |
| 29 | private: |
| 27 | 30 | _ListClass m_obj; |
| 28 | 31 | }; |
| 29 | 32 | |
| r26894 | r26895 | |
| 31 | 34 | { |
| 32 | 35 | m_num_elements = numElements; |
| 33 | 36 | m_list = new entry_t[m_num_elements]; |
| 34 | | m_ptr = m_list; |
| 35 | | m_ptr--; |
| 37 | m_count = 0; |
| 36 | 38 | } |
| 37 | 39 | |
| 38 | 40 | ATTR_COLD netlist_list_t(const netlist_list_t &rhs) |
| 39 | 41 | { |
| 40 | 42 | m_num_elements = rhs.capacity(); |
| 41 | 43 | m_list = new entry_t[m_num_elements]; |
| 42 | | m_ptr = m_list; |
| 43 | | m_ptr--; |
| 44 | m_count = 0; |
| 44 | 45 | for (int i=0; i<rhs.count(); i++) |
| 45 | 46 | { |
| 46 | 47 | this->add(rhs[i]); |
| r26894 | r26895 | |
| 64 | 65 | |
| 65 | 66 | ATTR_HOT inline void add(const _ListClass elem) |
| 66 | 67 | { |
| 67 | | if (m_ptr-m_list >= m_num_elements - 1) |
| 68 | if (m_count >= m_num_elements) |
| 68 | 69 | resize(m_num_elements * 2); |
| 69 | 70 | |
| 70 | | (++m_ptr)->m_obj = elem; |
| 71 | m_list[m_count++].m_obj = elem; |
| 71 | 72 | } |
| 72 | 73 | |
| 73 | 74 | ATTR_HOT inline void resize(const int new_size) |
| r26894 | r26895 | |
| 76 | 77 | entry_t *m_new = new entry_t[new_size]; |
| 77 | 78 | entry_t *pd = m_new; |
| 78 | 79 | |
| 79 | | for (entry_t *ps = m_list; ps <= m_ptr; ps++, pd++) |
| 80 | for (entry_t *ps = m_list; ps < m_list + cnt; ps++, pd++) |
| 80 | 81 | *pd = *ps; |
| 81 | 82 | delete[] m_list; |
| 82 | 83 | m_list = m_new; |
| 83 | | m_ptr = m_list + cnt - 1; |
| 84 | m_count = cnt; |
| 84 | 85 | m_num_elements = new_size; |
| 85 | 86 | } |
| 86 | 87 | |
| 87 | 88 | ATTR_HOT inline void remove(const _ListClass elem) |
| 88 | 89 | { |
| 89 | | for (entry_t *i = m_list; i <= m_ptr; i++) |
| 90 | for (int i =0; i < m_count; i++) |
| 90 | 91 | { |
| 91 | | if (i->object() == elem) |
| 92 | if (m_list[i].object() == elem) |
| 92 | 93 | { |
| 93 | | while (i < m_ptr) |
| 94 | m_count --; |
| 95 | while (i < m_count) |
| 94 | 96 | { |
| 95 | | *i = *(i+1); |
| 97 | m_list[i] = m_list[i+1]; |
| 96 | 98 | i++; |
| 97 | 99 | } |
| 98 | | m_ptr--; |
| 99 | 100 | return; |
| 100 | 101 | } |
| 101 | 102 | } |
| r26894 | r26895 | |
| 103 | 104 | |
| 104 | 105 | ATTR_HOT inline bool contains(const _ListClass elem) const |
| 105 | 106 | { |
| 106 | | for (entry_t *i = m_list; i <= m_ptr; i++) |
| 107 | for (entry_t *i = m_list; i < m_list + m_count; i++) |
| 107 | 108 | { |
| 108 | 109 | if (i->object() == elem) |
| 109 | 110 | return true; |
| r26894 | r26895 | |
| 111 | 112 | return false; |
| 112 | 113 | } |
| 113 | 114 | |
| 114 | | ATTR_HOT inline entry_t *first() const { return (m_ptr >= m_list ? &m_list[0] : NULL ); } |
| 115 | | ATTR_HOT inline entry_t *next(entry_t *lc) const { return (lc < last() ? lc + 1 : NULL ); } |
| 116 | | ATTR_HOT inline entry_t *last() const { return m_ptr; } |
| 117 | | ATTR_HOT inline int count() const { return m_ptr - m_list + 1; } |
| 118 | | ATTR_HOT inline bool empty() const { return (m_ptr < m_list); } |
| 119 | | ATTR_HOT inline void reset() { m_ptr = m_list - 1; } |
| 115 | ATTR_HOT inline entry_t *first() const { return ((m_count > 0) ? &m_list[0] : NULL ); } |
| 116 | ATTR_HOT inline entry_t *next(entry_t *lc) const { return ((lc < last()) ? lc + 1 : NULL ); } |
| 117 | ATTR_HOT inline entry_t *last() const { return &m_list[m_count -1]; } |
| 118 | ATTR_HOT inline int count() const { return m_count; } |
| 119 | ATTR_HOT inline bool empty() const { return (m_count == 0); } |
| 120 | ATTR_HOT inline void reset() { m_count = 0; } |
| 120 | 121 | ATTR_HOT inline int capacity() const { return m_num_elements; } |
| 121 | 122 | |
| 122 | 123 | ATTR_COLD void reset_and_free() |
| 123 | 124 | { |
| 124 | | for (entry_t *i = m_list; i <= m_ptr; i++) |
| 125 | for (entry_t *i = m_list; i < m_list + m_count; i++) |
| 125 | 126 | { |
| 126 | 127 | delete i->object(); |
| 127 | 128 | } |
| r26894 | r26895 | |
| 132 | 133 | ATTR_HOT inline const _ListClass& operator[](const int & index) const { return m_list[index].m_obj; } |
| 133 | 134 | |
| 134 | 135 | private: |
| 135 | | entry_t * m_ptr; |
| 136 | int m_count; |
| 136 | 137 | entry_t * m_list; |
| 137 | 138 | int m_num_elements; |
| 138 | 139 | //_ListClass m_list[_NumElements]; |
trunk/src/emu/netlist/devices/nld_solver.c
| r26894 | r26895 | |
| 47 | 47 | NL_VERBOSE_OUT(("Added terminal\n")); |
| 48 | 48 | break; |
| 49 | 49 | case netlist_terminal_t::INPUT: |
| 50 | | if (!m_inps.contains(&p->netdev())) |
| 51 | | m_inps.add(&p->netdev()); |
| 50 | if (!m_inps.contains(p)) |
| 51 | m_inps.add(p); |
| 52 | 52 | NL_VERBOSE_OUT(("Added input\n")); |
| 53 | 53 | break; |
| 54 | 54 | default: |
| r26894 | r26895 | |
| 68 | 68 | |
| 69 | 69 | ATTR_HOT inline void netlist_matrix_solver_t::update_inputs() |
| 70 | 70 | { |
| 71 | | for (dev_list_t::entry_t *p = m_inps.first(); p != NULL; p = m_inps.next(p)) |
| 71 | for (netlist_core_terminal_t::list_t::entry_t *p = m_inps.first(); p != NULL; p = m_inps.next(p)) |
| 72 | 72 | { |
| 73 | | p->object()->update_dev(); |
| 73 | if (p->object()->net().m_last.Analog != p->object()->net().m_cur.Analog) |
| 74 | { |
| 75 | p->object()->netdev().update_dev(); |
| 76 | } |
| 74 | 77 | } |
| 78 | for (netlist_core_terminal_t::list_t::entry_t *p = m_inps.first(); p != NULL; p = m_inps.next(p)) |
| 79 | { |
| 80 | p->object()->net().m_last.Analog = p->object()->net().m_cur.Analog; |
| 81 | } |
| 82 | |
| 75 | 83 | } |
| 76 | 84 | |
| 77 | 85 | |
| 78 | 86 | ATTR_HOT inline bool netlist_matrix_solver_t::solve() |
| 79 | 87 | { |
| 80 | | bool resched = false; |
| 88 | bool resched; |
| 89 | // FIXME: There may be situations where we *could* need more than one iteration for dynamic elements |
| 81 | 90 | |
| 82 | | /* update all non-linear devices */ |
| 83 | | for (dev_list_t::entry_t *p = m_dynamic.first(); p != NULL; p = m_dynamic.next(p)) |
| 84 | | switch (p->object()->family()) |
| 85 | | { |
| 86 | | case netlist_device_t::DIODE: |
| 87 | | static_cast<NETLIB_NAME(D) *>(p->object())->update_terminals(); |
| 88 | | break; |
| 89 | | default: |
| 90 | | p->object()->update_terminals(); |
| 91 | | break; |
| 92 | | } |
| 91 | int resched_cnt = (is_dynamic() ? /* 0 */ 1 : 1); |
| 92 | ATTR_UNUSED netlist_net_t *last_resched_net = NULL; |
| 93 | 93 | |
| 94 | | for (netlist_net_t::list_t::entry_t *pn = m_nets.first(); pn != NULL; pn = m_nets.next(pn)) |
| 95 | | { |
| 96 | | netlist_net_t *net = pn->object(); |
| 94 | do { |
| 95 | resched = false; |
| 96 | /* update all non-linear devices */ |
| 97 | for (dev_list_t::entry_t *p = m_dynamic.first(); p != NULL; p = m_dynamic.next(p)) |
| 98 | switch (p->object()->family()) |
| 99 | { |
| 100 | case netlist_device_t::DIODE: |
| 101 | static_cast<NETLIB_NAME(D) *>(p->object())->update_terminals(); |
| 102 | break; |
| 103 | default: |
| 104 | p->object()->update_terminals(); |
| 105 | break; |
| 106 | } |
| 97 | 107 | |
| 98 | | double gtot = 0; |
| 99 | | double gabs = 0; |
| 100 | | double iIdr = 0; |
| 101 | | const netlist_net_t::terminal_list_t &terms = net->m_terms; |
| 102 | | #if 1 |
| 103 | | switch (terms.count()) |
| 104 | | { |
| 105 | | case 1: |
| 106 | | { |
| 107 | | const netlist_terminal_t *pt = terms.first()->object(); |
| 108 | | gtot = pt->m_gt; |
| 109 | | gabs = fabs(pt->m_go); |
| 110 | | iIdr = pt->m_Idr + pt->m_go * pt->m_otherterm->net().Q_Analog(); |
| 111 | | } |
| 112 | | break; |
| 113 | | case 2: |
| 114 | | { |
| 115 | | const netlist_terminal_t *pt1 = terms[0]; |
| 116 | | const netlist_terminal_t *pt2 = terms[1]; |
| 117 | | gtot = pt1->m_gt + pt2->m_gt; |
| 118 | | gabs = fabs(pt1->m_go) + fabs(pt2->m_go); |
| 119 | | iIdr = pt1->m_Idr + pt1->m_go * pt1->m_otherterm->net().Q_Analog() |
| 120 | | + pt2->m_Idr + pt2->m_go * pt2->m_otherterm->net().Q_Analog(); |
| 121 | | } |
| 122 | | break; |
| 123 | | case 3: |
| 124 | | { |
| 125 | | const netlist_terminal_t *pt1 = terms[0]; |
| 126 | | const netlist_terminal_t *pt2 = terms[1]; |
| 127 | | const netlist_terminal_t *pt3 = terms[2]; |
| 128 | | gtot = pt1->m_gt + pt2->m_gt + pt3->m_gt; |
| 129 | | gabs = fabs(pt1->m_go) + fabs(pt2->m_go) + fabs(pt3->m_go); |
| 130 | | iIdr = pt1->m_Idr + pt1->m_go * pt1->m_otherterm->net().Q_Analog() |
| 131 | | + pt2->m_Idr + pt2->m_go * pt2->m_otherterm->net().Q_Analog() |
| 132 | | + pt3->m_Idr + pt3->m_go * pt3->m_otherterm->net().Q_Analog(); |
| 133 | | } |
| 134 | | break; |
| 135 | | default: |
| 136 | | for (netlist_net_t::terminal_list_t::entry_t *e = terms.first(); e != NULL; e = terms.next(e)) |
| 137 | | { |
| 138 | | netlist_terminal_t *pt = e->object(); |
| 139 | | gtot += pt->m_gt; |
| 140 | | gabs += fabs(pt->m_go); |
| 141 | | iIdr += pt->m_Idr + pt->m_go * pt->m_otherterm->net().Q_Analog(); |
| 142 | | } |
| 143 | | break; |
| 144 | | } |
| 145 | | #else |
| 146 | | for (netlist_net_t::terminal_list_t::entry_t *e = terms.first(); e != NULL; e = terms.next(e)) |
| 147 | | { |
| 148 | | netlist_terminal_t *pt = e->object(); |
| 149 | | gtot += pt->m_gt; |
| 150 | | gabs += fabs(pt->m_go); |
| 151 | | iIdr += pt->m_Idr + pt->m_go * pt->m_otherterm->net().Q_Analog(); |
| 152 | | } |
| 153 | | #endif |
| 154 | | double new_val; |
| 155 | | gabs *= m_convergence_factor; |
| 156 | | if (gabs > gtot) |
| 157 | | new_val = (net->m_cur.Analog * gabs + iIdr) / (gtot + gabs); |
| 158 | | else |
| 159 | | new_val = iIdr / gtot; |
| 108 | for (netlist_net_t::list_t::entry_t *pn = m_nets.first(); pn != NULL; pn = m_nets.next(pn)) |
| 109 | { |
| 110 | netlist_net_t *net = pn->object(); |
| 111 | const netlist_net_t::terminal_list_t &terms = net->m_terms; |
| 160 | 112 | |
| 161 | | if (fabs(new_val - net->m_cur.Analog) > m_accuracy) |
| 162 | | resched = true; |
| 163 | | net->m_cur.Analog = net->m_new.Analog = new_val; |
| 113 | double gtot = 0; |
| 114 | double gabs = 0; |
| 115 | double iIdr = 0; |
| 116 | double new_val; |
| 164 | 117 | |
| 165 | | NL_VERBOSE_OUT(("Info: %d\n", pn->object()->m_num_cons)); |
| 166 | | //NL_VERBOSE_OUT(("New: %lld %f %f\n", netlist().time().as_raw(), netlist().time().as_double(), new_val)); |
| 167 | | } |
| 118 | for (int i = 0; i < terms.count(); i++) |
| 119 | { |
| 120 | gtot += terms[i]->m_gt; |
| 121 | gabs += fabs(terms[i]->m_go); |
| 122 | iIdr += terms[i]->m_Idr + terms[i]->m_go * terms[i]->m_otherterm->net().Q_Analog(); |
| 123 | } |
| 124 | |
| 125 | gabs *= m_convergence_factor; |
| 126 | if (gabs > gtot) |
| 127 | new_val = (net->m_cur.Analog * gabs + iIdr) / (gtot + gabs); |
| 128 | else |
| 129 | new_val = iIdr / gtot; |
| 130 | |
| 131 | if (fabs(new_val - net->m_cur.Analog) > m_accuracy) |
| 132 | { |
| 133 | resched = true; |
| 134 | last_resched_net = net; |
| 135 | } |
| 136 | |
| 137 | net->m_cur.Analog = net->m_new.Analog = new_val; |
| 138 | |
| 139 | NL_VERBOSE_OUT(("Info: %d\n", pn->object()->m_num_cons)); |
| 140 | //NL_VERBOSE_OUT(("New: %lld %f %f\n", netlist().time().as_raw(), netlist().time().as_double(), new_val)); |
| 141 | } |
| 142 | resched_cnt++; |
| 143 | } while ((resched && (resched_cnt < m_resched_loops)) || (resched_cnt <= 1)); |
| 144 | |
| 145 | if (!resched) |
| 146 | update_inputs(); |
| 147 | //if (resched) |
| 148 | //printf("Resched on net %s first term %s\n", last_resched_net->name().cstr(), last_resched_net->m_terms[0]->name().cstr()); |
| 149 | |
| 168 | 150 | return resched; |
| 169 | 151 | } |
| 170 | 152 | |
| r26894 | r26895 | |
| 174 | 156 | |
| 175 | 157 | typedef netlist_net_t::list_t *net_groups_t; |
| 176 | 158 | |
| 177 | | static bool already_processed(net_groups_t groups, int &cur_group, netlist_net_t *net) |
| 159 | ATTR_COLD static bool already_processed(net_groups_t groups, int &cur_group, netlist_net_t *net) |
| 178 | 160 | { |
| 179 | 161 | if (net->isRailNet()) |
| 180 | 162 | return true; |
| r26894 | r26895 | |
| 186 | 168 | return false; |
| 187 | 169 | } |
| 188 | 170 | |
| 189 | | static void process_net(net_groups_t groups, int &cur_group, netlist_net_t *net) |
| 171 | ATTR_COLD static void process_net(net_groups_t groups, int &cur_group, netlist_net_t *net) |
| 190 | 172 | { |
| 191 | 173 | /* add the net */ |
| 192 | 174 | if (net->m_head == NULL) |
| r26894 | r26895 | |
| 219 | 201 | |
| 220 | 202 | register_param("ACCURACY", m_accuracy, 1e-3); |
| 221 | 203 | register_param("CONVERG", m_convergence, 0.3); |
| 204 | register_param("RESCHED_LOOPS", m_resched_loops, 15); |
| 222 | 205 | |
| 223 | 206 | // internal staff |
| 224 | 207 | |
| r26894 | r26895 | |
| 251 | 234 | |
| 252 | 235 | } |
| 253 | 236 | |
| 254 | | NETLIB_FUNC_VOID(solver, post_start, ()) |
| 255 | | { |
| 256 | | netlist_net_t::list_t groups[100]; |
| 257 | | int cur_group = -1; |
| 258 | | |
| 259 | | SOLVER_VERBOSE_OUT(("Scanning net groups ...\n")); |
| 260 | | // determine net groups |
| 261 | | for (netlist_net_t::list_t::entry_t *pn = netlist().m_nets.first(); pn != NULL; pn = netlist().m_nets.next(pn)) |
| 262 | | { |
| 263 | | if (!already_processed(groups, cur_group, pn->object())) |
| 264 | | { |
| 265 | | cur_group++; |
| 266 | | process_net(groups, cur_group, pn->object()); |
| 267 | | } |
| 268 | | } |
| 269 | | |
| 270 | | // setup the solvers |
| 271 | | SOLVER_VERBOSE_OUT(("Found %d net groups in %d nets\n", cur_group + 1, m_nets.count())); |
| 272 | | for (int i = 0; i <= cur_group; i++) |
| 273 | | { |
| 274 | | netlist_matrix_solver_t *ms = new netlist_matrix_solver_t(); |
| 275 | | ms->m_accuracy = m_accuracy.Value(); |
| 276 | | ms->m_convergence_factor = m_convergence.Value(); |
| 277 | | ms->setup(groups[i], *this); |
| 278 | | m_mat_solvers.add(ms); |
| 279 | | SOLVER_VERBOSE_OUT(("%d ==> %d nets %s\n", i, groups[i].count(), groups[i].first()->object()->m_head->name().cstr())); |
| 280 | | SOLVER_VERBOSE_OUT((" has %s elements\n", ms->is_dynamic() ? "dynamic" : "no dynamic")); |
| 281 | | } |
| 282 | | |
| 283 | | } |
| 284 | | |
| 285 | 237 | NETLIB_UPDATE(solver) |
| 286 | 238 | { |
| 287 | | //m_Q.setToNoCheck(!m_Q.new_Q(), m_inc ); |
| 288 | | //OUTLOGIC(m_Q, !m_Q.net().new_Q(), m_inc ); |
| 289 | | |
| 290 | | bool resched = false; |
| 291 | | int resched_cnt = 0; |
| 292 | 239 | netlist_time now = netlist().time(); |
| 293 | 240 | netlist_time delta = now - m_last_step; |
| 294 | 241 | |
| r26894 | r26895 | |
| 305 | 252 | bool global_resched = false; |
| 306 | 253 | for (netlist_matrix_solver_t::list_t::entry_t *e = m_mat_solvers.first(); e != NULL; e = m_mat_solvers.next(e)) |
| 307 | 254 | { |
| 308 | | resched_cnt = (e->object()->is_dynamic() ? 0 : 1); |
| 309 | | do { |
| 310 | | resched = e->object()->solve(); |
| 311 | | resched_cnt++; |
| 312 | | } while ((resched && (resched_cnt < 5)) || (resched_cnt <= 1)); |
| 313 | | global_resched = global_resched || resched; |
| 255 | global_resched = global_resched || e->object()->solve(); |
| 314 | 256 | } |
| 315 | | //if (global_resched) |
| 316 | | // printf("rescheduled\n"); |
| 317 | 257 | if (global_resched) |
| 318 | 258 | { |
| 319 | 259 | schedule(); |
| 320 | 260 | } |
| 321 | 261 | else |
| 322 | 262 | { |
| 323 | | /* update all inputs connected */ |
| 324 | | for (netlist_matrix_solver_t::list_t::entry_t *e = m_mat_solvers.first(); e != NULL; e = m_mat_solvers.next(e)) |
| 325 | | { |
| 326 | | e->object()->update_inputs(); |
| 327 | | } |
| 328 | | |
| 329 | 263 | /* step circuit */ |
| 330 | 264 | if (!m_Q_step.net().is_queued()) |
| 331 | 265 | m_Q_step.net().push_to_queue(m_inc); |
| 332 | 266 | } |
| 333 | 267 | |
| 334 | 268 | } |
| 269 | |
| 270 | ATTR_COLD void NETLIB_NAME(solver)::post_start() |
| 271 | { |
| 272 | netlist_net_t::list_t groups[100]; |
| 273 | int cur_group = -1; |
| 274 | |
| 275 | SOLVER_VERBOSE_OUT(("Scanning net groups ...\n")); |
| 276 | // determine net groups |
| 277 | for (netlist_net_t::list_t::entry_t *pn = netlist().m_nets.first(); pn != NULL; pn = netlist().m_nets.next(pn)) |
| 278 | { |
| 279 | if (!already_processed(groups, cur_group, pn->object())) |
| 280 | { |
| 281 | cur_group++; |
| 282 | process_net(groups, cur_group, pn->object()); |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | // setup the solvers |
| 287 | SOLVER_VERBOSE_OUT(("Found %d net groups in %d nets\n", cur_group + 1, netlist().m_nets.count())); |
| 288 | for (int i = 0; i <= cur_group; i++) |
| 289 | { |
| 290 | netlist_matrix_solver_t *ms = new netlist_matrix_solver_t(); |
| 291 | ms->m_accuracy = m_accuracy.Value(); |
| 292 | ms->m_convergence_factor = m_convergence.Value(); |
| 293 | ms->m_resched_loops = m_resched_loops.Value(); |
| 294 | ms->setup(groups[i], *this); |
| 295 | m_mat_solvers.add(ms); |
| 296 | SOLVER_VERBOSE_OUT(("%d ==> %d nets %s\n", i, groups[i].count(), groups[i].first()->object()->m_head->name().cstr())); |
| 297 | SOLVER_VERBOSE_OUT((" has %s elements\n", ms->is_dynamic() ? "dynamic" : "no dynamic")); |
| 298 | SOLVER_VERBOSE_OUT((" has %s elements\n", ms->is_timestep() ? "timestep" : "no timestep")); |
| 299 | } |
| 300 | |
| 301 | } |