trunk/src/emu/netlist/devices/net_lib.h
| r26182 | r26183 | |
| 64 | 64 | // this is a bad hack |
| 65 | 65 | #define USE_OLD7493 (0) |
| 66 | 66 | |
| 67 | |
| 67 | 68 | // ---------------------------------------------------------------------------------------- |
| 69 | // 2 terminal devices |
| 70 | // ---------------------------------------------------------------------------------------- |
| 71 | |
| 72 | #define NETDEV_R(_name, _R) \ |
| 73 | NET_REGISTER_DEV(R, _name) \ |
| 74 | NETDEV_PARAMI(_name, R, _R) \ |
| 75 | |
| 76 | |
| 77 | // ---------------------------------------------------------------------------------------- |
| 68 | 78 | // Special chips |
| 69 | 79 | // ---------------------------------------------------------------------------------------- |
| 70 | 80 | |
| r26182 | r26183 | |
| 77 | 87 | #define NETDEV_ANALOG_INPUT(_name) \ |
| 78 | 88 | NET_REGISTER_DEV(analog_input, _name) |
| 79 | 89 | #define NETDEV_CALLBACK(_name, _IN) \ |
| 80 | | NET_REGISTER_DEV(analog_callback, _name) \ |
| 90 | NET_REGISTER_DEV(analog_callback, _name) \ |
| 81 | 91 | NET_CONNECT(_name, IN, _IN) |
| 82 | 92 | #define NETDEV_SWITCH2(_name, _i1, _i2) \ |
| 83 | 93 | NET_REGISTER_DEV(nicMultiSwitch, _name) \ |
| r26182 | r26183 | |
| 241 | 251 | // ---------------------------------------------------------------------------------------- |
| 242 | 252 | |
| 243 | 253 | |
| 244 | | NETLIB_DEVICE_WITH_PARAMS(clock, |
| 245 | | netlist_ttl_input_t m_feedback; |
| 246 | | netlist_ttl_output_t m_Q; |
| 247 | 254 | |
| 248 | | netlist_param_t m_freq; |
| 249 | | netlist_time m_inc; |
| 250 | | ); |
| 251 | 255 | |
| 252 | 256 | NETLIB_DEVICE_WITH_PARAMS(nicMultiSwitch, |
| 253 | 257 | netlist_analog_input_t m_I[8]; |
| r26182 | r26183 | |
| 301 | 305 | netlist_param_t m_C; |
| 302 | 306 | netlist_param_t m_VS; |
| 303 | 307 | netlist_param_t m_VL; |
| 308 | |
| 309 | double nicNE555N_cv(); |
| 310 | double nicNE555N_clamp(const double v, const double a, const double b); |
| 311 | |
| 304 | 312 | ); |
| 305 | 313 | |
| 306 | 314 | NETLIB_SIGNAL(nic7430, 8, 0, 0); |
trunk/src/emu/netlist/devices/net_lib.c
| r26182 | r26183 | |
| 78 | 78 | printf("%s: %d %d\n", name().cstr(), (UINT32) (netlist().time().as_raw() / 1000000), INPLOGIC(m_I)); |
| 79 | 79 | } |
| 80 | 80 | |
| 81 | | NETLIB_START(clock) |
| 82 | | { |
| 83 | | register_output("Q", m_Q); |
| 84 | | //register_input("FB", m_feedback); |
| 85 | 81 | |
| 86 | | register_param("FREQ", m_freq, 7159000.0 * 5); |
| 87 | | m_inc = netlist_time::from_hz(m_freq.Value()*2); |
| 88 | | |
| 89 | | register_link_internal(m_feedback, m_Q, netlist_input_t::INP_STATE_ACTIVE); |
| 90 | | |
| 91 | | } |
| 92 | | |
| 93 | | NETLIB_UPDATE_PARAM(clock) |
| 94 | | { |
| 95 | | m_inc = netlist_time::from_hz(m_freq.Value()*2); |
| 96 | | } |
| 97 | | |
| 98 | | NETLIB_UPDATE(clock) |
| 99 | | { |
| 100 | | //m_Q.setToNoCheck(!m_Q.new_Q(), m_inc ); |
| 101 | | OUTLOGIC(m_Q, !m_Q.net().new_Q(), m_inc ); |
| 102 | | } |
| 103 | | |
| 104 | 82 | NETLIB_START(nicMultiSwitch) |
| 105 | 83 | { |
| 106 | 84 | static const char *sIN[8] = { "i1", "i2", "i3", "i4", "i5", "i6", "i7", "i8" }; |
| r26182 | r26183 | |
| 223 | 201 | m_last = false; |
| 224 | 202 | } |
| 225 | 203 | |
| 226 | | INLINE double nicNE555N_cv(NETLIB_NAME(nicNE555N_MSTABLE) &dev) |
| 204 | inline double NETLIB_NAME(nicNE555N_MSTABLE)::nicNE555N_cv() |
| 227 | 205 | { |
| 228 | | return (dev.m_CV.is_highz() ? 0.67 * dev.m_VS.Value() : dev.INPANALOG(dev.m_CV)); |
| 206 | return (m_CV.is_highz() ? 0.67 * m_VS.Value() : INPANALOG(m_CV)); |
| 229 | 207 | } |
| 230 | 208 | |
| 231 | | INLINE double nicNE555N_clamp(NETLIB_NAME(nicNE555N_MSTABLE) &dev, const double v, const double a, const double b) |
| 209 | inline double NETLIB_NAME(nicNE555N_MSTABLE)::nicNE555N_clamp(const double v, const double a, const double b) |
| 232 | 210 | { |
| 233 | 211 | double ret = v; |
| 234 | | if (ret > dev.m_VS.Value() - a) |
| 235 | | ret = dev.m_VS.Value() - a; |
| 212 | if (ret > m_VS.Value() - a) |
| 213 | ret = m_VS.Value() - a; |
| 236 | 214 | if (ret < b) |
| 237 | 215 | ret = b; |
| 238 | 216 | return ret; |
| r26182 | r26183 | |
| 246 | 224 | { |
| 247 | 225 | update_param(); // FIXME : m_CV should be on a sub device ... |
| 248 | 226 | |
| 249 | | double vt = nicNE555N_clamp(*this, nicNE555N_cv(*this), 0.7, 1.4); |
| 227 | double vt = nicNE555N_clamp(nicNE555N_cv(), 0.7, 1.4); |
| 250 | 228 | bool bthresh = (INPANALOG(m_THRESHOLD) > vt); |
| 251 | | bool btrig = (INPANALOG(m_trigger) > nicNE555N_clamp(*this, nicNE555N_cv(*this) * 0.5, 0.7, 1.4)); |
| 229 | bool btrig = (INPANALOG(m_trigger) > nicNE555N_clamp(nicNE555N_cv() * 0.5, 0.7, 1.4)); |
| 252 | 230 | bool out = m_last; |
| 253 | 231 | |
| 254 | 232 | if (!btrig) |
| r26182 | r26183 | |
| 624 | 602 | register_output(C, "QC", C.m_Q); |
| 625 | 603 | register_output(D, "QD", D.m_Q); |
| 626 | 604 | |
| 627 | | //B.register_link_internal(B.m_I, A.m_Q); |
| 628 | 605 | register_link_internal(C, C.m_I, B.m_Q, netlist_input_t::INP_STATE_HL); |
| 629 | 606 | register_link_internal(D, D.m_I, C.m_Q, netlist_input_t::INP_STATE_HL); |
| 630 | 607 | |
| r26182 | r26183 | |
| 972 | 949 | |
| 973 | 950 | static const net_device_t_base_factory *netregistry[] = |
| 974 | 951 | { |
| 952 | ENTRY(R, NETDEV_R) |
| 975 | 953 | ENTRY(ttl_const, NETDEV_TTL_CONST) |
| 976 | 954 | ENTRY(analog_const, NETDEV_ANALOG_CONST) |
| 977 | 955 | ENTRY(logic_input, NETDEV_LOGIC_INPUT) |
trunk/src/emu/netlist/nl_base.c
| r26182 | r26183 | |
| 216 | 216 | m_setup->register_output(*this, dev, name, port); |
| 217 | 217 | } |
| 218 | 218 | |
| 219 | void netlist_device_t::register_terminal(const astring &name, netlist_terminal_t &port) |
| 220 | { |
| 221 | m_setup->register_terminal(*this,*this,name, port); |
| 222 | } |
| 223 | |
| 219 | 224 | void netlist_device_t::register_output(const astring &name, netlist_output_t &port) |
| 220 | 225 | { |
| 221 | 226 | m_setup->register_output(*this,*this,name, port); |
| r26182 | r26183 | |
| 234 | 239 | void netlist_device_t::register_link_internal(netlist_core_device_t &dev, netlist_input_t &in, netlist_output_t &out, netlist_input_t::net_input_state aState) |
| 235 | 240 | { |
| 236 | 241 | in.init_input(dev, aState); |
| 237 | | out.init_terminal(dev); |
| 242 | // ensure we are not yet initialized ... |
| 243 | if (!out.net().isRailNet()) |
| 244 | out.init_terminal(dev); |
| 238 | 245 | //if (in.state() != net_input_t::INP_STATE_PASSIVE) |
| 239 | 246 | out.net().register_con(in); |
| 240 | 247 | } |
| r26182 | r26183 | |
| 274 | 281 | m_last.Q = 0; |
| 275 | 282 | }; |
| 276 | 283 | |
| 284 | ATTR_COLD void netlist_net_t::merge_net(netlist_net_t *othernet) |
| 285 | { |
| 286 | if (othernet == NULL) |
| 287 | return; // Nothing to do |
| 288 | |
| 289 | if (this->isRailNet() && othernet->isRailNet()) |
| 290 | fatalerror("Trying to merge to rail nets\n"); |
| 291 | |
| 292 | if (othernet->isRailNet()) |
| 293 | othernet->merge_net(this); |
| 294 | else |
| 295 | { |
| 296 | netlist_terminal_t *p = othernet->m_head; |
| 297 | if (p == NULL) |
| 298 | return; |
| 299 | if (m_head == NULL) |
| 300 | { |
| 301 | m_head = p; |
| 302 | m_head->set_net(*this); |
| 303 | p = p->m_update_list_next; |
| 304 | } |
| 305 | while (p != NULL) |
| 306 | { |
| 307 | netlist_terminal_t *pn = p->m_update_list_next; |
| 308 | p->m_update_list_next = m_head; |
| 309 | p->set_net(*this); |
| 310 | m_head = p; |
| 311 | p = pn; |
| 312 | } |
| 313 | othernet->m_head = NULL; // FIXME: othernet needs to be free'd from memory |
| 314 | } |
| 315 | } |
| 316 | |
| 277 | 317 | ATTR_COLD void netlist_net_t::register_con(netlist_terminal_t &terminal) |
| 278 | 318 | { |
| 279 | 319 | terminal.set_net(*this); |
| r26182 | r26183 | |
| 306 | 346 | { |
| 307 | 347 | assert(m_num_cons != 0); |
| 308 | 348 | |
| 309 | | const UINT32 masks[4] = { 1, 5, 3, 1 }; |
| 310 | | m_cur = m_new; |
| 311 | | m_in_queue = 2; /* mark as taken ... */ |
| 312 | | |
| 313 | | const UINT32 mask = masks[ (m_last.Q << 1) | m_cur.Q ]; |
| 314 | | |
| 315 | | netlist_terminal_t *p = m_head; |
| 316 | | switch (m_num_cons) |
| 317 | | { |
| 318 | | case 2: |
| 319 | | update_dev(p, mask); |
| 320 | | p = p->m_update_list_next; |
| 321 | | case 1: |
| 322 | | update_dev(p, mask); |
| 323 | | break; |
| 324 | | default: |
| 349 | //assert(this->isRailNet()); |
| 350 | if (UNEXPECTED(!this->isRailNet())) |
| 351 | { |
| 352 | /* only inputs and terminals connected |
| 353 | * approach: |
| 354 | * |
| 355 | * a) Update voltage on this net |
| 356 | * b) Update devices |
| 357 | * c) If difference old - new > trigger schedule immediate update |
| 358 | * of number of updates < max_update_count |
| 359 | * else clear number of updates |
| 360 | */ |
| 361 | m_in_queue = 2; /* mark as taken ... */ |
| 362 | double gtot = 0; |
| 363 | double iIdr = 0; |
| 364 | netlist_terminal_t *p = m_head; |
| 325 | 365 | do |
| 326 | 366 | { |
| 327 | | update_dev(p, mask); |
| 367 | p->netdev().update_dev(); |
| 368 | gtot += p->m_g; |
| 369 | iIdr += p->m_Idr; |
| 370 | |
| 328 | 371 | p = p->m_update_list_next; |
| 329 | 372 | } while (p != NULL); |
| 330 | | break; |
| 331 | | } |
| 332 | | m_last = m_cur; |
| 373 | m_new.Analog = iIdr / gtot; |
| 374 | printf("New: %f\n", m_new.Analog); |
| 375 | } |
| 376 | else |
| 377 | { |
| 378 | |
| 379 | const UINT32 masks[4] = { 1, 5, 3, 1 }; |
| 380 | m_cur = m_new; |
| 381 | m_in_queue = 2; /* mark as taken ... */ |
| 382 | |
| 383 | const UINT32 mask = masks[ (m_last.Q << 1) | m_cur.Q ]; |
| 384 | |
| 385 | netlist_terminal_t *p = m_head; |
| 386 | switch (m_num_cons) |
| 387 | { |
| 388 | case 2: |
| 389 | update_dev(p, mask); |
| 390 | p = p->m_update_list_next; |
| 391 | case 1: |
| 392 | update_dev(p, mask); |
| 393 | break; |
| 394 | default: |
| 395 | do |
| 396 | { |
| 397 | update_dev(p, mask); |
| 398 | p = p->m_update_list_next; |
| 399 | } while (p != NULL); |
| 400 | break; |
| 401 | } |
| 402 | m_last = m_cur; |
| 403 | } |
| 333 | 404 | } |
| 334 | 405 | |
| 335 | 406 | // ---------------------------------------------------------------------------------------- |
trunk/src/emu/netlist/nl_base.h
| r26182 | r26183 | |
| 170 | 170 | #define NETLIB_UPDATE_PARAM(_chip) ATTR_HOT ATTR_ALIGN void NETLIB_NAME(_chip) :: update_param(void) |
| 171 | 171 | #define NETLIB_FUNC_VOID(_chip, _name, _params) ATTR_HOT ATTR_ALIGN inline void NETLIB_NAME(_chip) :: _name _params |
| 172 | 172 | |
| 173 | #define NETLIB_DEVICE_BASE(_name, _pclass, _extra, _priv) \ |
| 174 | class _name : public _pclass \ |
| 175 | { \ |
| 176 | public: \ |
| 177 | _name() \ |
| 178 | : _pclass() { } \ |
| 179 | protected: \ |
| 180 | _extra \ |
| 181 | ATTR_HOT void update(); \ |
| 182 | ATTR_HOT void start(); \ |
| 183 | _priv \ |
| 184 | } |
| 185 | |
| 186 | #define NETLIB_DEVICE_DERIVED(_name, _pclass, _priv) \ |
| 187 | NETLIB_DEVICE_BASE(NETLIB_NAME(_name), NETLIB_NAME(_pclass), , _priv) |
| 188 | |
| 173 | 189 | #define NETLIB_DEVICE(_name, _priv) \ |
| 174 | | class NETLIB_NAME(_name) : public netlist_device_t \ |
| 175 | | { \ |
| 176 | | public: \ |
| 177 | | NETLIB_NAME(_name) () \ |
| 178 | | : netlist_device_t() { } \ |
| 179 | | protected: \ |
| 180 | | ATTR_HOT void update(); \ |
| 181 | | ATTR_HOT void start(); \ |
| 182 | | _priv \ |
| 183 | | } |
| 190 | NETLIB_DEVICE_BASE(NETLIB_NAME(_name), netlist_device_t, , _priv) |
| 184 | 191 | |
| 185 | 192 | #define NETLIB_SUBDEVICE(_name, _priv) \ |
| 186 | 193 | class NETLIB_NAME(_name) : public netlist_core_device_t \ |
| r26182 | r26183 | |
| 195 | 202 | } |
| 196 | 203 | |
| 197 | 204 | #define NETLIB_DEVICE_WITH_PARAMS(_name, _priv) \ |
| 198 | | class NETLIB_NAME(_name) : public netlist_device_t \ |
| 199 | | { \ |
| 200 | | public: \ |
| 201 | | NETLIB_NAME(_name) () \ |
| 202 | | : netlist_device_t() { } \ |
| 203 | | ATTR_HOT void update_param(); \ |
| 204 | | ATTR_HOT void update(); \ |
| 205 | | ATTR_HOT void start(); \ |
| 206 | | /* protected: */ \ |
| 207 | | _priv \ |
| 208 | | } |
| 205 | NETLIB_DEVICE_BASE(NETLIB_NAME(_name), netlist_device_t, \ |
| 206 | ATTR_HOT void update_param(); \ |
| 207 | , _priv) |
| 209 | 208 | |
| 209 | #define NETLIB_DEVICE_WITH_PARAMS_DERIVED(_name, _pclass, _priv) \ |
| 210 | NETLIB_DEVICE_BASE(NETLIB_NAME(_name), NETLIB_NAME(_pclass), \ |
| 211 | ATTR_HOT void update_param(); \ |
| 212 | , _priv) |
| 213 | |
| 210 | 214 | // ---------------------------------------------------------------------------------------- |
| 211 | 215 | // forward definitions |
| 212 | 216 | // ---------------------------------------------------------------------------------------- |
| r26182 | r26183 | |
| 287 | 291 | |
| 288 | 292 | ATTR_COLD netlist_terminal_t(const type_t atype, const family_t afamily) |
| 289 | 293 | : netlist_object_t(atype, afamily) |
| 294 | , m_Idr(0.0) |
| 295 | , m_g(NETLIST_GMIN) |
| 290 | 296 | , m_update_list_next(NULL) |
| 291 | 297 | , m_netdev(NULL) |
| 292 | 298 | , m_net(NULL) |
| 293 | 299 | , m_state(INP_STATE_ACTIVE) |
| 294 | 300 | {} |
| 295 | 301 | |
| 302 | ATTR_COLD netlist_terminal_t() |
| 303 | : netlist_object_t(TERMINAL, ANALOG) |
| 304 | , m_Idr(0.0) |
| 305 | , m_update_list_next(NULL) |
| 306 | , m_netdev(NULL) |
| 307 | , m_net(NULL) |
| 308 | , m_state(INP_STATE_ACTIVE) |
| 309 | {} |
| 310 | |
| 296 | 311 | ATTR_COLD virtual void init_terminal(netlist_core_device_t &dev); |
| 297 | 312 | |
| 298 | 313 | ATTR_COLD void set_net(netlist_net_t &anet) { m_net = &anet; } |
| 314 | ATTR_COLD bool has_net() { return (m_net != NULL); } |
| 299 | 315 | |
| 300 | 316 | ATTR_HOT inline const netlist_net_t & RESTRICT net() const { return *m_net;} |
| 301 | 317 | ATTR_HOT inline netlist_net_t & RESTRICT net() { return *m_net;} |
| r26182 | r26183 | |
| 306 | 322 | |
| 307 | 323 | ATTR_HOT inline netlist_core_device_t & RESTRICT netdev() const { return *m_netdev; } |
| 308 | 324 | |
| 325 | double m_Idr; // drive current |
| 326 | double m_g; // conductance |
| 327 | |
| 309 | 328 | netlist_terminal_t *m_update_list_next; |
| 310 | 329 | |
| 311 | 330 | private: |
| r26182 | r26183 | |
| 421 | 440 | ATTR_COLD netlist_net_t(const type_t atype, const family_t afamily); |
| 422 | 441 | |
| 423 | 442 | ATTR_COLD void register_con(netlist_terminal_t &terminal); |
| 443 | ATTR_COLD void merge_net(netlist_net_t *othernet); |
| 424 | 444 | ATTR_COLD void register_railterminal(netlist_terminal_t &mr) |
| 425 | 445 | { |
| 426 | 446 | assert(m_railterminal == NULL); |
| r26182 | r26183 | |
| 447 | 467 | ATTR_HOT inline const netlist_sig_t last_Q() const { return m_last.Q; } |
| 448 | 468 | ATTR_HOT inline const netlist_sig_t new_Q() const { return m_new.Q; } |
| 449 | 469 | |
| 470 | ATTR_HOT inline const double Q_Analog() const |
| 471 | { |
| 472 | //assert(object_type(SIGNAL_MASK) == SIGNAL_ANALOG); |
| 473 | assert(family() == ANALOG); |
| 474 | return m_cur.Analog; |
| 475 | } |
| 476 | |
| 477 | ATTR_HOT inline void push_to_queue(const netlist_time &delay); |
| 478 | ATTR_HOT bool is_queued() { return m_in_queue == 1; } |
| 479 | |
| 450 | 480 | protected: |
| 451 | 481 | |
| 452 | 482 | /* prohibit use in device functions |
| r26182 | r26183 | |
| 458 | 488 | assert(family() == LOGIC); |
| 459 | 489 | return m_cur.Q; |
| 460 | 490 | } |
| 461 | | ATTR_HOT inline const double Q_Analog() const |
| 462 | | { |
| 463 | | //assert(object_type(SIGNAL_MASK) == SIGNAL_ANALOG); |
| 464 | | assert(family() == ANALOG); |
| 465 | | return m_cur.Analog; |
| 466 | | } |
| 467 | 491 | |
| 468 | | ATTR_HOT inline void push_to_queue(const netlist_time &delay); |
| 469 | | |
| 470 | 492 | hybrid_t m_last; |
| 471 | 493 | hybrid_t m_cur; |
| 472 | 494 | hybrid_t m_new; |
| r26182 | r26183 | |
| 670 | 692 | |
| 671 | 693 | ATTR_COLD void register_sub(netlist_core_device_t &dev, const astring &name); |
| 672 | 694 | |
| 695 | ATTR_COLD void register_terminal(const astring &name, netlist_terminal_t &port); |
| 696 | |
| 673 | 697 | ATTR_COLD void register_output(const astring &name, netlist_output_t &out); |
| 674 | 698 | ATTR_COLD void register_output(netlist_core_device_t &dev, const astring &name, netlist_output_t &out); |
| 675 | 699 | |
| r26182 | r26183 | |
| 850 | 874 | double m_high_V; |
| 851 | 875 | }; |
| 852 | 876 | |
| 877 | // ---------------------------------------------------------------------------------------- |
| 878 | // nld_twoterm |
| 879 | // ---------------------------------------------------------------------------------------- |
| 853 | 880 | |
| 881 | class nld_twoterm : public netlist_device_t |
| 882 | { |
| 883 | public: |
| 884 | nld_twoterm() |
| 885 | : netlist_device_t(), m_g(0.0), m_V(0.0), m_I(0.0) |
| 886 | { |
| 887 | } |
| 888 | |
| 889 | netlist_terminal_t m_P; |
| 890 | netlist_terminal_t m_N; |
| 891 | |
| 892 | protected: |
| 893 | virtual void start() |
| 894 | { |
| 895 | } |
| 896 | |
| 897 | ATTR_HOT ATTR_ALIGN virtual void update() |
| 898 | { |
| 899 | m_N.m_Idr = (m_P.net().Q_Analog() - m_V) * m_g + m_I; |
| 900 | m_P.m_Idr = (m_N.net().Q_Analog() + m_V) * m_g - m_I; |
| 901 | printf("%f %f %f %f\n", m_N.m_Idr, m_P.m_Idr, m_N.net().Q_Analog(), m_P.net().Q_Analog()); |
| 902 | if (!m_N.net().is_queued() && !m_N.net().isRailNet()) |
| 903 | m_N.net().push_to_queue(NLTIME_FROM_NS(10)); |
| 904 | if (!m_P.net().is_queued() && !m_P.net().isRailNet() ) |
| 905 | m_P.net().push_to_queue(NLTIME_FROM_NS(10)); |
| 906 | } |
| 907 | |
| 908 | double m_g; // conductance |
| 909 | double m_V; // internal voltage source |
| 910 | double m_I; // internal current source |
| 911 | private: |
| 912 | }; |
| 913 | |
| 914 | class nld_R : public nld_twoterm |
| 915 | { |
| 916 | public: |
| 917 | nld_R() |
| 918 | : nld_twoterm() |
| 919 | { |
| 920 | } |
| 921 | |
| 922 | netlist_param_t m_R; |
| 923 | |
| 924 | protected: |
| 925 | void start() |
| 926 | { |
| 927 | register_terminal("1", m_P); |
| 928 | register_terminal("2", m_N); |
| 929 | |
| 930 | register_param("R", m_R, NETLIST_GMIN); |
| 931 | } |
| 932 | |
| 933 | virtual void update_param() |
| 934 | { |
| 935 | m_g = 1.0 / m_R.Value(); |
| 936 | m_P.m_g = m_g; |
| 937 | m_N.m_g = m_g; |
| 938 | } |
| 939 | |
| 940 | private: |
| 941 | }; |
| 942 | |
| 854 | 943 | // ---------------------------------------------------------------------------------------- |
| 855 | 944 | // Inline implementations |
| 856 | 945 | // ---------------------------------------------------------------------------------------- |
trunk/src/emu/netlist/nl_setup.c
| r26182 | r26183 | |
| 23 | 23 | |
| 24 | 24 | netlist_setup_t::netlist_setup_t(netlist_base_t &netlist) |
| 25 | 25 | : m_netlist(netlist) |
| 26 | , m_proxy_cnt(0) |
| 26 | 27 | { |
| 27 | 28 | NETLIST_NAME(base)(*this); |
| 28 | 29 | } |
| r26182 | r26183 | |
| 110 | 111 | fatalerror("Error adding output %s to terminal list\n", name.cstr()); |
| 111 | 112 | } |
| 112 | 113 | |
| 114 | void netlist_setup_t::register_terminal(netlist_core_device_t &dev, netlist_core_device_t &upd_dev, const astring &name, netlist_terminal_t &out) |
| 115 | { |
| 116 | NL_VERBOSE_OUT(("output %s\n", name.cstr())); |
| 117 | assert(out.isType(netlist_terminal_t::TERMINAL)); |
| 118 | astring temp = dev.name(); |
| 119 | temp.cat("."); |
| 120 | temp.cat(name); |
| 121 | out.init_terminal(upd_dev); |
| 122 | if (!(m_terminals.add(temp, &out, false)==TMERR_NONE)) |
| 123 | fatalerror("Error adding output %s to terminal list\n", name.cstr()); |
| 124 | } |
| 125 | |
| 113 | 126 | void netlist_setup_t::register_input(netlist_device_t &dev, netlist_core_device_t &upd_dev, const astring &name, netlist_input_t &inp, netlist_input_t::net_input_state type) |
| 114 | 127 | { |
| 115 | 128 | NL_VERBOSE_OUT(("input %s\n", name.cstr())); |
| r26182 | r26183 | |
| 176 | 189 | return *ret; |
| 177 | 190 | } |
| 178 | 191 | |
| 192 | netlist_terminal_t &netlist_setup_t::find_terminal(const astring &terminal_in) |
| 193 | { |
| 194 | const astring &tname = resolve_alias(terminal_in); |
| 195 | netlist_terminal_t *ret; |
| 196 | |
| 197 | ret = dynamic_cast<netlist_terminal_t *>(m_terminals.find(tname)); |
| 198 | /* look for default */ |
| 199 | if (ret == NULL) |
| 200 | { |
| 201 | /* look for ".Q" std output */ |
| 202 | astring s = tname; |
| 203 | s.cat(".Q"); |
| 204 | ret = dynamic_cast<netlist_terminal_t *>(m_terminals.find(s)); |
| 205 | } |
| 206 | if (ret == NULL) |
| 207 | fatalerror("terminal %s(%s) not found!\n", terminal_in.cstr(), tname.cstr()); |
| 208 | NL_VERBOSE_OUT(("Found input %s\n", tname.cstr())); |
| 209 | return *ret; |
| 210 | } |
| 211 | |
| 179 | 212 | netlist_param_t &netlist_setup_t::find_param(const astring ¶m_in) |
| 180 | 213 | { |
| 181 | 214 | const astring &outname = resolve_alias(param_in); |
| r26182 | r26183 | |
| 188 | 221 | return *ret; |
| 189 | 222 | } |
| 190 | 223 | |
| 191 | | void netlist_setup_t::resolve_inputs(void) |
| 224 | |
| 225 | void netlist_setup_t::connect_input_output(netlist_input_t &in, netlist_output_t &out) |
| 192 | 226 | { |
| 193 | | NL_VERBOSE_OUT(("Resolving ...\n")); |
| 194 | | int proxy_cnt = 0; |
| 195 | | for (tagmap_astring_t::entry_t *entry = m_links.first(); entry != NULL; entry = m_links.next(entry)) |
| 196 | | { |
| 197 | | const astring *sout = entry->object(); |
| 198 | | astring sin = entry->tag(); |
| 199 | | netlist_input_t *in = dynamic_cast<netlist_input_t *>(m_terminals.find(sin)); |
| 227 | if (out.isFamily(netlist_terminal_t::ANALOG) && in.isFamily(netlist_terminal_t::LOGIC)) |
| 228 | { |
| 229 | nld_a_to_d_proxy *proxy = new nld_a_to_d_proxy(in); |
| 230 | astring x = ""; |
| 231 | x.printf("proxy_ad_%d", m_proxy_cnt++); |
| 200 | 232 | |
| 201 | | if (in == NULL) |
| 202 | | fatalerror("Unable to find %s\n", sin.cstr()); |
| 233 | proxy->init(*this, x.cstr()); |
| 234 | register_dev(proxy); |
| 203 | 235 | |
| 204 | | netlist_output_t &out = find_output(sout->cstr()); |
| 205 | | if (out.isFamily(netlist_terminal_t::ANALOG) && in->isFamily(netlist_terminal_t::LOGIC)) |
| 206 | | { |
| 207 | | nld_a_to_d_proxy *proxy = new nld_a_to_d_proxy(*in); |
| 208 | | astring x = ""; |
| 209 | | x.printf("proxy_ad_%d", proxy_cnt++); |
| 236 | proxy->m_Q.net().register_con(in); |
| 237 | out.net().register_con(proxy->m_I); |
| 210 | 238 | |
| 211 | | proxy->init(*this, x.cstr()); |
| 212 | | register_dev(proxy); |
| 239 | } |
| 240 | else if (out.isFamily(netlist_terminal_t::LOGIC) && in.isFamily(netlist_terminal_t::ANALOG)) |
| 241 | { |
| 242 | //printf("here 1\n"); |
| 243 | nld_d_to_a_proxy *proxy = new nld_d_to_a_proxy(out); |
| 244 | astring x = ""; |
| 245 | x.printf("proxy_da_%d", m_proxy_cnt++); |
| 246 | proxy->init(*this, x.cstr()); |
| 247 | register_dev(proxy); |
| 213 | 248 | |
| 214 | | proxy->m_Q.net().register_con(*in); |
| 215 | | out.net().register_con(proxy->m_I); |
| 249 | proxy->m_Q.net().register_con(in); |
| 250 | out.net().register_con(proxy->m_I); |
| 251 | } |
| 252 | else |
| 253 | { |
| 254 | out.net().register_con(in); |
| 255 | } |
| 256 | } |
| 216 | 257 | |
| 217 | | } |
| 218 | | else if (out.isFamily(netlist_terminal_t::LOGIC) && in->isFamily(netlist_terminal_t::ANALOG)) |
| 219 | | { |
| 220 | | //printf("here 1\n"); |
| 221 | | nld_d_to_a_proxy *proxy = new nld_d_to_a_proxy(out); |
| 222 | | astring x = ""; |
| 223 | | x.printf("proxy_da_%d", proxy_cnt++); |
| 224 | | proxy->init(*this, x.cstr()); |
| 225 | | register_dev(proxy); |
| 258 | // FIXME: optimize code ... |
| 259 | void netlist_setup_t::connect_terminal_output(netlist_terminal_t &in, netlist_output_t &out) |
| 260 | { |
| 261 | if (out.isFamily(netlist_terminal_t::ANALOG)) |
| 262 | { |
| 263 | /* no proxy needed, just merge existing terminal net */ |
| 264 | if (in.has_net()) |
| 265 | out.net().merge_net(&in.net()); |
| 266 | else |
| 267 | out.net().register_con(in); |
| 226 | 268 | |
| 227 | | proxy->m_Q.net().register_con(*in); |
| 228 | | out.net().register_con(proxy->m_I); |
| 229 | | } |
| 230 | | else |
| 231 | | { |
| 232 | | out.net().register_con(*in); |
| 233 | | } |
| 234 | | } |
| 269 | } |
| 270 | else if (out.isFamily(netlist_terminal_t::LOGIC)) |
| 271 | { |
| 272 | //printf("here 1\n"); |
| 273 | nld_d_to_a_proxy *proxy = new nld_d_to_a_proxy(out); |
| 274 | astring x = ""; |
| 275 | x.printf("proxy_da_%d", m_proxy_cnt++); |
| 276 | proxy->init(*this, x.cstr()); |
| 277 | register_dev(proxy); |
| 235 | 278 | |
| 236 | | /* find the main clock ... */ |
| 237 | | for (tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry)) |
| 238 | | { |
| 239 | | netlist_device_t *dev = entry->object(); |
| 240 | | if (dynamic_cast<NETLIB_NAME(mainclock)*>(dev) != NULL) |
| 241 | | { |
| 242 | | m_netlist.set_mainclock_dev(dynamic_cast<NETLIB_NAME(mainclock)*>(dev)); |
| 243 | | } |
| 244 | | } |
| 279 | out.net().register_con(proxy->m_I); |
| 245 | 280 | |
| 246 | | /* print all outputs */ |
| 247 | | for (tagmap_terminal_t::entry_t *entry = m_terminals.first(); entry != NULL; entry = m_terminals.next(entry)) |
| 248 | | { |
| 249 | | ATTR_UNUSED netlist_output_t *out = dynamic_cast<netlist_output_t *>(entry->object()); |
| 250 | | //if (out != NULL) |
| 251 | | //VERBOSE_OUT(("%s %d\n", out->netdev()->name(), *out->Q_ptr())); |
| 252 | | } |
| 281 | if (in.has_net()) |
| 282 | proxy->m_Q.net().merge_net(&in.net()); |
| 283 | else |
| 284 | proxy->m_Q.net().register_con(in); |
| 285 | } |
| 286 | else |
| 287 | { |
| 288 | fatalerror("Netlist: Severe Error"); |
| 289 | } |
| 290 | } |
| 253 | 291 | |
| 292 | void netlist_setup_t::connect_terminals(netlist_terminal_t &in, netlist_terminal_t &out) |
| 293 | { |
| 294 | assert(in.isType(netlist_terminal_t::TERMINAL)); |
| 295 | assert(out.isType(netlist_terminal_t::TERMINAL)); |
| 254 | 296 | |
| 297 | if (in.has_net() && out.has_net()) |
| 298 | { |
| 299 | in.net().merge_net(&out.net()); |
| 300 | //in.net().register_con(out); |
| 301 | //in.net().register_con(in); |
| 302 | } |
| 303 | else if (out.has_net()) |
| 304 | { |
| 305 | out.net().register_con(in); |
| 306 | //out.net().register_con(out); |
| 307 | } |
| 308 | else if (in.has_net()) |
| 309 | { |
| 310 | in.net().register_con(out); |
| 311 | //in.net().register_con(in); |
| 312 | } |
| 313 | else |
| 314 | { |
| 315 | NL_VERBOSE_OUT(("adding net ...\n")); |
| 316 | in.set_net(*(new netlist_net_t(netlist_object_t::NET, netlist_object_t::ANALOG))); |
| 317 | in.net().init_object(netlist()); |
| 318 | in.net().register_con(out); |
| 319 | in.net().register_con(in); |
| 320 | } |
| 255 | 321 | } |
| 256 | 322 | |
| 323 | void netlist_setup_t::resolve_inputs(void) |
| 324 | { |
| 325 | NL_VERBOSE_OUT(("Searching for clocks ...\n")); |
| 326 | /* find the main clock ... */ |
| 327 | for (tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry)) |
| 328 | { |
| 329 | netlist_device_t *dev = entry->object(); |
| 330 | if (dynamic_cast<NETLIB_NAME(mainclock)*>(dev) != NULL) |
| 331 | { |
| 332 | m_netlist.set_mainclock_dev(dynamic_cast<NETLIB_NAME(mainclock)*>(dev)); |
| 333 | } |
| 334 | } |
| 335 | |
| 336 | NL_VERBOSE_OUT(("Resolving ...\n")); |
| 337 | for (tagmap_astring_t::entry_t *entry = m_links.first(); entry != NULL; entry = m_links.next(entry)) |
| 338 | { |
| 339 | const astring t1s = *entry->object(); |
| 340 | const astring t2s = entry->tag(); |
| 341 | netlist_terminal_t &t1 = find_terminal(t1s); |
| 342 | netlist_terminal_t &t2 = find_terminal(t2s); |
| 343 | |
| 344 | // FIXME: amend device design so that warnings can be turned into errors |
| 345 | // Only variable inputs have this issue |
| 346 | if (t1.isType(netlist_terminal_t::OUTPUT) && t2.isType(netlist_terminal_t::INPUT)) |
| 347 | { |
| 348 | if (t2.has_net()) |
| 349 | mame_printf_warning("Input %s already connected\n", t2s.cstr()); |
| 350 | connect_input_output(dynamic_cast<netlist_input_t &>(t2), dynamic_cast<netlist_output_t &>(t1)); |
| 351 | } |
| 352 | else if (t1.isType(netlist_terminal_t::INPUT) && t2.isType(netlist_terminal_t::OUTPUT)) |
| 353 | { |
| 354 | if (t1.has_net()) |
| 355 | mame_printf_warning("Input %s already connected\n", t1s.cstr()); |
| 356 | connect_input_output(dynamic_cast<netlist_input_t &>(t1), dynamic_cast<netlist_output_t &>(t2)); |
| 357 | } |
| 358 | else if (t1.isType(netlist_terminal_t::OUTPUT) && t2.isType(netlist_terminal_t::TERMINAL)) |
| 359 | { |
| 360 | connect_terminal_output(dynamic_cast<netlist_terminal_t &>(t2), dynamic_cast<netlist_output_t &>(t1)); |
| 361 | } |
| 362 | else if (t1.isType(netlist_terminal_t::TERMINAL) && t2.isType(netlist_terminal_t::OUTPUT)) |
| 363 | { |
| 364 | connect_terminal_output(dynamic_cast<netlist_terminal_t &>(t1), dynamic_cast<netlist_output_t &>(t2)); |
| 365 | } |
| 366 | else if (t1.isType(netlist_terminal_t::TERMINAL) && t2.isType(netlist_terminal_t::TERMINAL)) |
| 367 | { |
| 368 | connect_terminals(dynamic_cast<netlist_terminal_t &>(t1), dynamic_cast<netlist_terminal_t &>(t2)); |
| 369 | } |
| 370 | else |
| 371 | fatalerror("Connecting %s to %s not supported!\n", t1s.cstr(), t2s.cstr()); |
| 372 | } |
| 373 | |
| 374 | /* print all outputs */ |
| 375 | for (tagmap_terminal_t::entry_t *entry = m_terminals.first(); entry != NULL; entry = m_terminals.next(entry)) |
| 376 | { |
| 377 | ATTR_UNUSED netlist_output_t *out = dynamic_cast<netlist_output_t *>(entry->object()); |
| 378 | //if (out != NULL) |
| 379 | //VERBOSE_OUT(("%s %d\n", out->netdev()->name(), *out->Q_ptr())); |
| 380 | } |
| 381 | |
| 382 | |
| 383 | } |
| 384 | |
| 257 | 385 | void netlist_setup_t::step_devices_once(void) |
| 258 | 386 | { |
| 259 | 387 | /* make sure params are set now .. */ |
trunk/src/emu/netlist/nl_setup.h
| r26182 | r26183 | |
| 28 | 28 | NET_REGISTER_DEV(_type ## _ ## sig, _name) |
| 29 | 29 | #define NET_CONNECT(_name, _input, _output) \ |
| 30 | 30 | netlist.register_link(# _name "." # _input, # _output); |
| 31 | #define NET_C(_input, _output) \ |
| 32 | netlist.register_link(# _input , # _output); |
| 31 | 33 | #define NETDEV_PARAM(_name, _val) \ |
| 32 | 34 | netlist.find_param(# _name).initial(_val); |
| 35 | #define NETDEV_PARAMI(_name, _param, _val) \ |
| 36 | netlist.find_param(# _name "." # _param).initial(_val); |
| 33 | 37 | |
| 38 | |
| 34 | 39 | #define NETLIST_NAME(_name) netlist ## _ ## _name |
| 35 | 40 | |
| 36 | 41 | #define NETLIST_START(_name) \ |
| r26182 | r26183 | |
| 71 | 76 | netlist_device_t *register_dev(netlist_device_t *dev); |
| 72 | 77 | void remove_dev(const astring &name); |
| 73 | 78 | |
| 79 | void register_terminal(netlist_core_device_t &dev, netlist_core_device_t &upd_dev, const astring &name, netlist_terminal_t &out); |
| 74 | 80 | void register_output(netlist_core_device_t &dev, netlist_core_device_t &upd_dev, const astring &name, netlist_output_t &out); |
| 75 | 81 | void register_input(netlist_device_t &dev, netlist_core_device_t &upd_dev, const astring &name, netlist_input_t &inp, netlist_input_t::net_input_state type); |
| 76 | 82 | void register_alias(const astring &alias, const astring &out); |
| r26182 | r26183 | |
| 79 | 85 | void register_link(const astring &sin, const astring &sout); |
| 80 | 86 | |
| 81 | 87 | netlist_output_t &find_output(const astring &outname_in); |
| 88 | netlist_terminal_t &find_terminal(const astring &outname_in); |
| 82 | 89 | netlist_param_t &find_param(const astring ¶m_in); |
| 83 | 90 | |
| 84 | 91 | void register_callback(const astring &devname, netlist_output_delegate delegate); |
| r26182 | r26183 | |
| 105 | 112 | tagmap_param_t m_params; |
| 106 | 113 | tagmap_astring_t m_links; |
| 107 | 114 | |
| 115 | int m_proxy_cnt; |
| 116 | |
| 117 | void connect_terminals(netlist_terminal_t &in, netlist_terminal_t &out); |
| 118 | void connect_input_output(netlist_input_t &in, netlist_output_t &out); |
| 119 | void connect_terminal_output(netlist_terminal_t &in, netlist_output_t &out); |
| 120 | |
| 108 | 121 | netlist_output_t *find_output_exact(const astring &outname_in); |
| 109 | 122 | const astring &resolve_alias(const astring &name) const; |
| 110 | 123 | }; |