| Previous | 199869 Revisions | Next |
| r32162 Thursday 18th September, 2014 at 00:51:41 UTC by Alex Jackson |
|---|
| diexec.c: Cache a pointer directly to the machine scheduler at startup, to eliminate device().machine().scheduler() chains all over the place (nw) This change has been sitting in my local tree for months, from when I was (mostly unsuccessfully) working on c64 performance. It gives a small speedup to drivers with many tightly-interleaved executing devices (i.e. Commodore drivers) I didn't think it was worth making everyone do a clean build for such tiny gains but I didn't have the heart to chuck it. Since I'm already making another core-touching, clean-build-needed commit tonight, in it goes. |
| [src/emu] | diexec.c diexec.h schedule.c |
| r32161 | r32162 | |
|---|---|---|
| 493 | 493 | exec->m_totalcycles += ran; |
| 494 | 494 | |
| 495 | 495 | // update the local time for this CPU |
| 496 | attotime delta | |
| 496 | attotime delta(0, exec->m_attoseconds_per_cycle * ran); | |
| 497 | 497 | assert(delta >= attotime::zero); |
| 498 | 498 | exec->m_localtime += delta; |
| 499 | 499 | LOG((" %d ran, %d total, time = %s\n", ran, (INT32)exec->m_totalcycles, exec->m_localtime.as_string(PRECISION))); |
| r32161 | r32162 | |
|---|---|---|
| 146 | 146 | |
| 147 | 147 | bool device_execute_interface::executing() const |
| 148 | 148 | { |
| 149 | return (this == | |
| 149 | return (this == m_scheduler->currently_executing()); | |
| 150 | 150 | } |
| 151 | 151 | |
| 152 | 152 | |
| r32161 | r32162 | |
| 204 | 204 | void device_execute_interface::abort_timeslice() |
| 205 | 205 | { |
| 206 | 206 | // ignore if not the executing device |
| 207 | if ( | |
| 207 | if (!executing()) | |
| 208 | 208 | return; |
| 209 | 209 | |
| 210 | 210 | // swallow the remaining cycles |
| r32161 | r32162 | |
| 225 | 225 | void device_execute_interface::suspend_resume_changed() |
| 226 | 226 | { |
| 227 | 227 | // inform the scheduler |
| 228 | | |
| 228 | m_scheduler->suspend_resume_changed(); | |
| 229 | 229 | |
| 230 | 230 | // if we're active, synchronize |
| 231 | 231 | abort_timeslice(); |
| r32161 | r32162 | |
| 273 | 273 | suspend_until_trigger(TRIGGER_SUSPENDTIME + timetrig, true); |
| 274 | 274 | |
| 275 | 275 | // then set a timer for it |
| 276 | | |
| 276 | m_scheduler->timer_set(duration, FUNC(static_timed_trigger_callback), TRIGGER_SUSPENDTIME + timetrig, this); | |
| 277 | 277 | timetrig = (timetrig + 1) % 256; |
| 278 | 278 | } |
| 279 | 279 | |
| r32161 | r32162 | |
| 469 | 469 | |
| 470 | 470 | void device_execute_interface::interface_pre_start() |
| 471 | 471 | { |
| 472 | m_scheduler = &device().machine().scheduler(); | |
| 473 | ||
| 472 | 474 | // bind delegates |
| 473 | 475 | m_vblank_interrupt.bind_relative_to(*device().owner()); |
| 474 | 476 | m_timed_interrupt.bind_relative_to(*device().owner()); |
| r32161 | r32162 | |
| 483 | 485 | |
| 484 | 486 | // allocate timers if we need them |
| 485 | 487 | if (m_timed_interrupt_period != attotime::zero) |
| 486 | m_timedint_timer = | |
| 488 | m_timedint_timer = m_scheduler->timer_alloc(FUNC(static_trigger_periodic_interrupt), (void *)this); | |
| 487 | 489 | } |
| 488 | 490 | |
| 489 | 491 | |
| r32161 | r32162 | |
| 595 | 597 | m_divisor = attos; |
| 596 | 598 | |
| 597 | 599 | // re-compute the perfect interleave factor |
| 598 | | |
| 600 | m_scheduler->compute_perfect_interleave(); | |
| 599 | 601 | } |
| 600 | 602 | |
| 601 | 603 | |
| r32161 | r32162 | |
| 711 | 713 | |
| 712 | 714 | device_execute_interface::device_input::device_input() |
| 713 | 715 | : m_execute(NULL), |
| 714 | m_device(NULL), | |
| 715 | 716 | m_linenum(0), |
| 716 | 717 | m_stored_vector(0), |
| 717 | 718 | m_curvector(0), |
| r32161 | r32162 | |
| 730 | 731 | void device_execute_interface::device_input::start(device_execute_interface *execute, int linenum) |
| 731 | 732 | { |
| 732 | 733 | m_execute = execute; |
| 733 | m_device = &m_execute->device(); | |
| 734 | 734 | m_linenum = linenum; |
| 735 | 735 | |
| 736 | 736 | reset(); |
| 737 | 737 | |
| 738 | m_device->save_item(NAME(m_stored_vector), m_linenum); | |
| 739 | m_device->save_item(NAME(m_curvector), m_linenum); | |
| 740 | m_device->save_item(NAME(m_curstate), m_linenum); | |
| 738 | device_t &device = m_execute->device(); | |
| 739 | device.save_item(NAME(m_stored_vector), m_linenum); | |
| 740 | device.save_item(NAME(m_curvector), m_linenum); | |
| 741 | device.save_item(NAME(m_curstate), m_linenum); | |
| 741 | 742 | } |
| 742 | 743 | |
| 743 | 744 | |
| r32161 | r32162 | |
| 759 | 760 | |
| 760 | 761 | void device_execute_interface::device_input::set_state_synced(int state, int vector) |
| 761 | 762 | { |
| 762 | LOG(("set_state_synced('%s',%d,%d,%02x)\n", m_device | |
| 763 | LOG(("set_state_synced('%s',%d,%d,%02x)\n", m_execute->device().tag(), m_linenum, state, vector)); | |
| 763 | 764 | |
| 764 | if (TEMPLOG) printf("setline(%s,%d,%d,%d)\n", m_device | |
| 765 | if (TEMPLOG) printf("setline(%s,%d,%d,%d)\n", m_execute->device().tag(), m_linenum, state, (vector == USE_STORED_VECTOR) ? 0 : vector); | |
| 765 | 766 | assert(state == ASSERT_LINE || state == HOLD_LINE || state == CLEAR_LINE || state == PULSE_LINE); |
| 766 | 767 | |
| 767 | 768 | // treat PULSE_LINE as ASSERT+CLEAR |
| r32161 | r32162 | |
| 769 | 770 | { |
| 770 | 771 | // catch errors where people use PULSE_LINE for devices that don't support it |
| 771 | 772 | if (m_linenum != INPUT_LINE_NMI && m_linenum != INPUT_LINE_RESET) |
| 772 | throw emu_fatalerror("device '%s': PULSE_LINE can only be used for NMI and RESET lines\n", m_device | |
| 773 | throw emu_fatalerror("device '%s': PULSE_LINE can only be used for NMI and RESET lines\n", m_execute->device().tag()); | |
| 773 | 774 | |
| 774 | 775 | set_state_synced(ASSERT_LINE, vector); |
| 775 | 776 | set_state_synced(CLEAR_LINE, vector); |
| r32161 | r32162 | |
| 783 | 784 | m_qindex--; |
| 784 | 785 | empty_event_queue(); |
| 785 | 786 | event_index = m_qindex++; |
| 786 | logerror("Exceeded pending input line event queue on device '%s'!\n", m_device | |
| 787 | logerror("Exceeded pending input line event queue on device '%s'!\n", m_execute->device().tag()); | |
| 787 | 788 | } |
| 788 | 789 | |
| 789 | 790 | // enqueue the event |
| r32161 | r32162 | |
| 795 | 796 | |
| 796 | 797 | // if this is the first one, set the timer |
| 797 | 798 | if (event_index == 0) |
| 798 | m_execute-> | |
| 799 | m_execute->scheduler().synchronize(FUNC(static_empty_event_queue), 0, (void *)this); | |
| 799 | 800 | } |
| 800 | 801 | } |
| 801 | 802 | |
| r32161 | r32162 | |
| 811 | 812 | |
| 812 | 813 | void device_execute_interface::device_input::empty_event_queue() |
| 813 | 814 | { |
| 814 | if (TEMPLOG) printf("empty_queue(%s,%d,%d)\n", m_device | |
| 815 | if (TEMPLOG) printf("empty_queue(%s,%d,%d)\n", m_execute->device().tag(), m_linenum, m_qindex); | |
| 815 | 816 | // loop over all events |
| 816 | 817 | for (int curevent = 0; curevent < m_qindex; curevent++) |
| 817 | 818 | { |
| r32161 | r32162 | |
| 834 | 835 | // if we're clearing the line that was previously asserted, reset the device |
| 835 | 836 | else if (m_execute->suspended(SUSPEND_REASON_RESET)) |
| 836 | 837 | { |
| 837 | m_device | |
| 838 | m_execute->device().reset(); | |
| 838 | 839 | m_execute->resume(SUSPEND_REASON_RESET); |
| 839 | 840 | } |
| 840 | 841 | } |
| r32161 | r32162 | |
| 867 | 868 | break; |
| 868 | 869 | |
| 869 | 870 | default: |
| 870 | logerror("empty_event_queue device '%s', line %d, unknown state %d\n", m_device | |
| 871 | logerror("empty_event_queue device '%s', line %d, unknown state %d\n", m_execute->device().tag(), m_linenum, m_curstate); | |
| 871 | 872 | break; |
| 872 | 873 | } |
| 873 | 874 | |
| r32161 | r32162 | |
| 894 | 895 | // if the IRQ state is HOLD_LINE, clear it |
| 895 | 896 | if (m_curstate == HOLD_LINE) |
| 896 | 897 | { |
| 897 | LOG(("->set_irq_line('%s',%d,%d)\n", m_device | |
| 898 | LOG(("->set_irq_line('%s',%d,%d)\n", m_execute->device().tag(), m_linenum, CLEAR_LINE)); | |
| 898 | 899 | m_execute->execute_set_input(m_linenum, CLEAR_LINE); |
| 899 | 900 | m_curstate = CLEAR_LINE; |
| 900 | 901 | } |
| r32161 | r32162 | |
|---|---|---|
| 113 | 113 | |
| 114 | 114 | class emu_timer; |
| 115 | 115 | class screen_device; |
| 116 | class device_scheduler; | |
| 116 | 117 | |
| 117 | 118 | |
| 118 | 119 | // interrupt callback for VBLANK and timed interrupts |
| r32161 | r32162 | |
| 154 | 155 | static void static_set_irq_acknowledge_callback(device_t &device, device_irq_acknowledge_delegate callback); |
| 155 | 156 | |
| 156 | 157 | // execution management |
| 158 | device_scheduler &scheduler() const { assert(m_scheduler != NULL); return *m_scheduler; } | |
| 157 | 159 | bool executing() const; |
| 158 | 160 | INT32 cycles_remaining() const; |
| 159 | 161 | void eat_cycles(int cycles); |
| r32161 | r32162 | |
| 239 | 241 | int default_irq_callback(); |
| 240 | 242 | |
| 241 | 243 | device_execute_interface *m_execute;// pointer to the execute interface |
| 242 | device_t * m_device; // pointer to our device | |
| 243 | 244 | int m_linenum; // which input line we are |
| 244 | 245 | |
| 245 | 246 | INT32 m_stored_vector; // most recently written vector |
| r32161 | r32162 | |
| 253 | 254 | void empty_event_queue(); |
| 254 | 255 | }; |
| 255 | 256 | |
| 257 | // scheduler | |
| 258 | device_scheduler * m_scheduler; // pointer to the machine scheduler | |
| 259 | ||
| 256 | 260 | // configuration |
| 257 | 261 | bool m_disabled; // disabled from executing? |
| 258 | 262 | device_interrupt_delegate m_vblank_interrupt; // for interrupts tied to VBLANK |
| Previous | 199869 Revisions | Next |