trunk/src/emu/machine/netlist.c
| r26799 | r26800 | |
| 140 | 140 | |
| 141 | 141 | netlist_mame_device_t::netlist_mame_device_t(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 142 | 142 | : device_t(mconfig, NETLIST_CORE, "Netlist core device", tag, owner, clock, "netlist_core", __FILE__), |
| 143 | m_icount(0), |
| 144 | m_div(0), |
| 145 | m_rem(0), |
| 146 | m_old(netlist_time::zero), |
| 143 | 147 | m_netlist(NULL), |
| 144 | 148 | m_setup(NULL), |
| 145 | 149 | m_setup_func(NULL) |
| r26799 | r26800 | |
| 148 | 152 | |
| 149 | 153 | netlist_mame_device_t::netlist_mame_device_t(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *file) |
| 150 | 154 | : device_t(mconfig, type, name, tag, owner, clock, shortname, file), |
| 155 | m_icount(0), |
| 156 | m_div(0), |
| 157 | m_rem(0), |
| 158 | m_old(netlist_time::zero), |
| 151 | 159 | m_netlist(NULL), |
| 152 | 160 | m_setup(NULL), |
| 153 | 161 | m_setup_func(NULL) |
| r26799 | r26800 | |
| 170 | 178 | { |
| 171 | 179 | LOG_DEV_CALLS(("device_start %s\n", tag())); |
| 172 | 180 | |
| 181 | printf("clock is %d\n", clock()); |
| 182 | |
| 173 | 183 | m_netlist = global_alloc_clear(netlist_mame_t(*this)); |
| 174 | 184 | m_setup = global_alloc_clear(netlist_setup_t(*m_netlist)); |
| 175 | 185 | netlist().init_object(*m_netlist, "netlist"); |
| 176 | 186 | m_setup->init(); |
| 177 | 187 | |
| 178 | | netlist().set_clock_freq(this->clock()); |
| 179 | | |
| 180 | 188 | // register additional devices |
| 181 | 189 | |
| 182 | 190 | m_setup->factory().register_device<nld_analog_callback>( "NETDEV_CALLBACK", "nld_analog_callback"); |
| r26799 | r26800 | |
| 197 | 205 | m_setup->start_devices(); |
| 198 | 206 | m_setup->resolve_inputs(); |
| 199 | 207 | |
| 208 | netlist().save(NAME(m_rem)); |
| 209 | netlist().save(NAME(m_div)); |
| 210 | netlist().save(NAME(m_old)); |
| 211 | |
| 200 | 212 | save_state(); |
| 201 | 213 | |
| 214 | m_old = netlist_time::zero; |
| 215 | m_rem = 0; |
| 216 | |
| 202 | 217 | } |
| 203 | 218 | |
| 219 | void netlist_mame_device_t::device_clock_changed() |
| 220 | { |
| 221 | //printf("device_clock_changed\n"); |
| 222 | m_div = netlist_time::from_hz(clock()).as_raw(); |
| 223 | //m_rem = 0; |
| 224 | NL_VERBOSE_OUT(("Setting clock %" I64FMT "d and divisor %d\n", clockfreq, m_div)); |
| 225 | //printf("Setting clock %d and divisor %d\n", clock(), m_div); |
| 226 | } |
| 227 | |
| 228 | |
| 204 | 229 | void netlist_mame_device_t::device_reset() |
| 205 | 230 | { |
| 206 | 231 | LOG_DEV_CALLS(("device_reset\n")); |
| 232 | m_old = netlist_time::zero; |
| 233 | m_rem = 0; |
| 207 | 234 | netlist().reset(); |
| 208 | 235 | } |
| 209 | 236 | |
| r26799 | r26800 | |
| 236 | 263 | { |
| 237 | 264 | } |
| 238 | 265 | |
| 266 | ATTR_HOT ATTR_ALIGN void netlist_mame_device_t::update_time_x() |
| 267 | { |
| 268 | const netlist_time delta = netlist().time() - m_old + netlist_time::from_raw(m_rem); |
| 269 | m_old = netlist().time(); |
| 270 | m_icount -= divu_64x32_rem(delta.as_raw(), m_div, &m_rem); |
| 271 | } |
| 272 | |
| 273 | ATTR_HOT ATTR_ALIGN void netlist_mame_device_t::check_mame_abort_slice() |
| 274 | { |
| 275 | if (m_icount <= 0) |
| 276 | netlist().abort_current_queue_slice(); |
| 277 | } |
| 278 | |
| 239 | 279 | ATTR_COLD void netlist_mame_device_t::save_state() |
| 240 | 280 | { |
| 241 | 281 | for (pstate_entry_t::list_t::entry_t *p = netlist().save_list().first(); p != NULL; p = netlist().save_list().next(p)) |
| r26799 | r26800 | |
| 279 | 319 | device_state_interface(mconfig, *this), |
| 280 | 320 | device_disasm_interface(mconfig, *this), |
| 281 | 321 | device_memory_interface(mconfig, *this), |
| 282 | | m_program_config("program", ENDIANNESS_LITTLE, 8, 12, 0, ADDRESS_MAP_NAME(program_dummy)), |
| 283 | | m_icount(0) |
| 322 | m_program_config("program", ENDIANNESS_LITTLE, 8, 12, 0, ADDRESS_MAP_NAME(program_dummy)) |
| 284 | 323 | { |
| 285 | 324 | } |
| 286 | 325 | |
| r26799 | r26800 | |
| 352 | 391 | { |
| 353 | 392 | while (m_icount > 0) |
| 354 | 393 | { |
| 355 | | int m_temp = 1; |
| 356 | 394 | m_genPC++; |
| 357 | 395 | m_genPC &= 255; |
| 358 | 396 | debugger_instruction_hook(this, m_genPC); |
| 359 | | netlist().process_queue(m_temp); |
| 360 | | m_icount -= (1 - m_temp); |
| 397 | netlist().process_queue(netlist_time::from_raw(m_div)); |
| 398 | update_time_x(); |
| 361 | 399 | } |
| 362 | 400 | } |
| 363 | 401 | else |
| 364 | | netlist().process_queue(m_icount); |
| 402 | { |
| 403 | netlist().process_queue(netlist_time::from_raw(m_div) * m_icount); |
| 404 | update_time_x(); |
| 405 | } |
| 365 | 406 | } |
trunk/src/emu/machine/netlist.h
| r26799 | r26800 | |
| 56 | 56 | |
| 57 | 57 | // MAME specific configuration |
| 58 | 58 | |
| 59 | | #define MCFG_NETLIST_ADD(_tag, _setup ) \ |
| 60 | | MCFG_DEVICE_ADD(_tag, NETLIST_CPU, NETLIST_CLOCK) \ |
| 59 | #define MCFG_NETLIST_ADD(_tag, _setup, _clock ) \ |
| 60 | MCFG_DEVICE_ADD(_tag, NETLIST_CPU, _clock) \ |
| 61 | 61 | MCFG_NETLIST_SETUP(_setup) |
| 62 | 62 | |
| 63 | 63 | #define MCFG_NETLIST_REPLACE(_tag, _setup) \ |
| r26799 | r26800 | |
| 148 | 148 | ATTR_HOT inline netlist_setup_t &setup() { return *m_setup; } |
| 149 | 149 | ATTR_HOT inline netlist_mame_t &netlist() { return *m_netlist; } |
| 150 | 150 | |
| 151 | ATTR_HOT inline netlist_time last_time_update() { return m_old; } |
| 152 | ATTR_HOT void update_time_x(); |
| 153 | ATTR_HOT void check_mame_abort_slice(); |
| 154 | |
| 155 | int m_icount; |
| 156 | |
| 151 | 157 | protected: |
| 152 | 158 | // device_t overrides |
| 153 | 159 | virtual void device_config_complete(); |
| r26799 | r26800 | |
| 157 | 163 | virtual void device_post_load(); |
| 158 | 164 | virtual void device_pre_save(); |
| 159 | 165 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); |
| 166 | //virtual void device_debug_setup(); |
| 167 | virtual void device_clock_changed(); |
| 160 | 168 | |
| 169 | UINT32 m_div; |
| 170 | |
| 161 | 171 | private: |
| 162 | 172 | void save_state(); |
| 163 | 173 | |
| 164 | | netlist_mame_t *m_netlist; |
| 165 | | netlist_setup_t *m_setup; |
| 174 | /* timing support here - so sound can hijack it ... */ |
| 175 | UINT32 m_rem; |
| 176 | netlist_time m_old; |
| 166 | 177 | |
| 178 | netlist_mame_t * m_netlist; |
| 179 | netlist_setup_t * m_setup; |
| 180 | |
| 167 | 181 | void (*m_setup_func)(netlist_setup_t &); |
| 168 | 182 | }; |
| 169 | 183 | |
| r26799 | r26800 | |
| 241 | 255 | |
| 242 | 256 | private: |
| 243 | 257 | |
| 244 | | int m_icount; |
| 245 | 258 | int m_genPC; |
| 246 | 259 | |
| 247 | 260 | }; |
| r26799 | r26800 | |
| 368 | 381 | |
| 369 | 382 | ATTR_HOT void update() |
| 370 | 383 | { |
| 384 | m_cpu_device->update_time_x(); |
| 371 | 385 | m_callback(INPANALOG(m_in), m_cpu_device->local_time()); |
| 386 | m_cpu_device->check_mame_abort_slice(); |
| 372 | 387 | } |
| 373 | 388 | |
| 374 | 389 | private: |
trunk/src/emu/netlist/nl_base.c
| r26799 | r26800 | |
| 27 | 27 | manager.save_item(m_times, module + "." + "times"); |
| 28 | 28 | manager.save_item(&(m_name[0][0]), module + "." + "names", sizeof(m_name)); |
| 29 | 29 | } |
| 30 | |
| 30 | 31 | void netlist_queue_t::on_pre_save() |
| 31 | 32 | { |
| 32 | 33 | NL_VERBOSE_OUT(("on_pre_save\n")); |
| r26799 | r26800 | |
| 111 | 112 | : netlist_object_t(NETLIST, GENERIC), |
| 112 | 113 | m_time_ps(netlist_time::zero), |
| 113 | 114 | m_queue(*this), |
| 114 | | m_rem(0), |
| 115 | | m_div(NETLIST_DIV), |
| 116 | 115 | m_mainclock(NULL), |
| 117 | 116 | m_solver(NULL) |
| 118 | 117 | { |
| r26799 | r26800 | |
| 168 | 167 | ATTR_COLD void netlist_base_t::reset() |
| 169 | 168 | { |
| 170 | 169 | m_time_ps = netlist_time::zero; |
| 171 | | m_rem = 0; |
| 172 | 170 | m_queue.clear(); |
| 173 | 171 | if (m_mainclock != NULL) |
| 174 | 172 | m_mainclock->m_Q.net().set_time(netlist_time::zero); |
| r26799 | r26800 | |
| 188 | 186 | } |
| 189 | 187 | } |
| 190 | 188 | |
| 191 | | void netlist_base_t::set_clock_freq(UINT64 clockfreq) |
| 192 | | { |
| 193 | | m_div = netlist_time::from_hz(clockfreq).as_raw(); |
| 194 | | m_rem = 0; |
| 195 | | assert_always(m_div == NETLIST_DIV, "netlist: illegal clock!"); |
| 196 | | NL_VERBOSE_OUT(("Setting clock %" I64FMT "d and divisor %d\n", clockfreq, m_div)); |
| 197 | | } |
| 198 | 189 | |
| 199 | | ATTR_HOT ATTR_ALIGN inline void netlist_base_t::update_time(const netlist_time t, INT32 &atime) |
| 190 | ATTR_HOT ATTR_ALIGN void netlist_base_t::process_queue(const netlist_time delta) |
| 200 | 191 | { |
| 201 | | if (NETLIST_DIV_BITS == 0) |
| 202 | | { |
| 203 | | const netlist_time delta = t - m_time_ps; |
| 204 | | m_time_ps = t; |
| 205 | | atime -= delta.as_raw(); |
| 206 | | } else { |
| 207 | | const netlist_time delta = t - m_time_ps + netlist_time::from_raw(m_rem); |
| 208 | | m_time_ps = t; |
| 209 | | m_rem = delta.as_raw() & NETLIST_MASK; |
| 210 | | atime -= (delta.as_raw() >> NETLIST_DIV_BITS); |
| 192 | m_stop = m_time_ps + delta; |
| 211 | 193 | |
| 212 | | // The folling is suitable for non-power of 2 m_divs ... |
| 213 | | // atime -= divu_64x32_rem(delta.as_raw(), m_div, &m_rem); |
| 214 | | } |
| 215 | | } |
| 194 | if (m_mainclock == NULL) |
| 195 | { |
| 196 | while ( (m_time_ps < m_stop) && (m_queue.is_not_empty())) |
| 197 | { |
| 198 | const netlist_queue_t::entry_t &e = m_queue.pop(); |
| 199 | m_time_ps = e.time(); |
| 200 | e.object().update_devs(); |
| 216 | 201 | |
| 217 | | ATTR_HOT ATTR_ALIGN void netlist_base_t::process_queue(INT32 &atime) |
| 218 | | { |
| 219 | | if (m_mainclock == NULL) |
| 220 | | { |
| 221 | | while ( (atime > 0) && (m_queue.is_not_empty())) |
| 222 | | { |
| 223 | | const netlist_queue_t::entry_t &e = m_queue.pop(); |
| 224 | | update_time(e.time(), atime); |
| 202 | add_to_stat(m_perf_out_processed, 1); |
| 203 | if (FATAL_ERROR_AFTER_NS) |
| 204 | if (time() > NLTIME_FROM_NS(FATAL_ERROR_AFTER_NS)) |
| 205 | xfatalerror("Stopped"); |
| 206 | } |
| 207 | if (m_queue.is_empty()) |
| 208 | m_time_ps = m_stop; |
| 225 | 209 | |
| 226 | | //if (FATAL_ERROR_AFTER_NS) |
| 227 | | // NL_VERBOSE_OUT(("%s\n", e.object().netdev()->name().cstr()); |
| 210 | } else { |
| 211 | netlist_net_t &mcQ = m_mainclock->m_Q.net(); |
| 212 | const netlist_time inc = m_mainclock->m_inc; |
| 228 | 213 | |
| 229 | | e.object().update_devs(); |
| 214 | while (m_time_ps < m_stop) |
| 215 | { |
| 216 | if (m_queue.is_not_empty()) |
| 217 | { |
| 218 | while (m_queue.peek().time() > mcQ.time()) |
| 219 | { |
| 220 | m_time_ps = mcQ.time(); |
| 221 | NETLIB_NAME(mainclock)::mc_update(mcQ, m_time_ps + inc); |
| 222 | } |
| 230 | 223 | |
| 231 | | add_to_stat(m_perf_out_processed, 1); |
| 224 | const netlist_queue_t::entry_t &e = m_queue.pop(); |
| 225 | m_time_ps = e.time(); |
| 226 | e.object().update_devs(); |
| 232 | 227 | |
| 233 | | if (FATAL_ERROR_AFTER_NS) |
| 234 | | if (time() > NLTIME_FROM_NS(FATAL_ERROR_AFTER_NS)) |
| 235 | | xfatalerror("Stopped"); |
| 236 | | } |
| 228 | } else { |
| 229 | m_time_ps = mcQ.time(); |
| 230 | NETLIB_NAME(mainclock)::mc_update(mcQ, m_time_ps + inc); |
| 231 | } |
| 232 | if (FATAL_ERROR_AFTER_NS) |
| 233 | if (time() > NLTIME_FROM_NS(FATAL_ERROR_AFTER_NS)) |
| 234 | xfatalerror("Stopped"); |
| 237 | 235 | |
| 238 | | if (atime > 0) |
| 239 | | { |
| 240 | | m_time_ps += netlist_time::from_raw(atime * m_div); |
| 241 | | atime = 0; |
| 242 | | } |
| 243 | | } else { |
| 244 | | netlist_net_t &mcQ = m_mainclock->m_Q.net(); |
| 245 | | const netlist_time inc = m_mainclock->m_inc; |
| 246 | | |
| 247 | | while (atime > 0) |
| 248 | | { |
| 249 | | if (m_queue.is_not_empty()) |
| 250 | | { |
| 251 | | while (m_queue.peek().time() > mcQ.time()) |
| 252 | | { |
| 253 | | update_time(mcQ.time(), atime); |
| 254 | | |
| 255 | | NETLIB_NAME(mainclock)::mc_update(mcQ, time() + inc); |
| 256 | | |
| 257 | | } |
| 258 | | const netlist_queue_t::entry_t &e = m_queue.pop(); |
| 259 | | |
| 260 | | update_time(e.time(), atime); |
| 261 | | |
| 262 | | e.object().update_devs(); |
| 263 | | |
| 264 | | } else { |
| 265 | | update_time(mcQ.time(), atime); |
| 266 | | |
| 267 | | NETLIB_NAME(mainclock)::mc_update(mcQ, time() + inc); |
| 268 | | } |
| 269 | | if (FATAL_ERROR_AFTER_NS) |
| 270 | | if (time() > NLTIME_FROM_NS(FATAL_ERROR_AFTER_NS)) |
| 271 | | xfatalerror("Stopped"); |
| 272 | | |
| 273 | | add_to_stat(m_perf_out_processed, 1); |
| 274 | | } |
| 275 | | |
| 276 | | if (atime > 0) |
| 277 | | { |
| 278 | | m_time_ps += netlist_time::from_raw(atime * m_div); |
| 279 | | atime = 0; |
| 280 | | } |
| 281 | | } |
| 236 | add_to_stat(m_perf_out_processed, 1); |
| 237 | } |
| 238 | } |
| 282 | 239 | } |
| 283 | 240 | |
| 284 | 241 | ATTR_COLD void netlist_base_t::xfatalerror(const char *format, ...) const |