1 // license:BSD-3-Clause 2 // copyright-holders:Aaron Giles 3 /*************************************************************************** 4 5 schedule.h 6 7 Core device execution and scheduling engine. 8 9 ***************************************************************************/ 10 11 #pragma once 12 13 #ifndef __EMU_H__ 14 #error Dont include this file directly; include emu.h instead. 15 #endif 16 17 #ifndef MAME_EMU_SCHEDULE_H 18 #define MAME_EMU_SCHEDULE_H 19 20 21 //************************************************************************** 22 // MACROS 23 //************************************************************************** 24 25 #define TIMER_CALLBACK_MEMBER(name) void name(void *ptr, s32 param) 26 27 28 //************************************************************************** 29 // TYPE DEFINITIONS 30 //************************************************************************** 31 32 // timer callbacks look like this 33 typedef named_delegate<void (void *, s32)> timer_expired_delegate; 34 35 // ======================> emu_timer 36 37 class emu_timer 38 { 39 friend class device_scheduler; 40 friend class simple_list<emu_timer>; 41 friend class fixed_allocator<emu_timer>; 42 friend class resource_pool_object<emu_timer>; 43 44 // construction/destruction 45 emu_timer(); 46 ~emu_timer(); 47 48 // allocation and re-use 49 emu_timer &init(running_machine &machine, timer_expired_delegate callback, void *ptr, bool temporary); 50 emu_timer &init(device_t &device, device_timer_id id, void *ptr, bool temporary); 51 emu_timer &release(); 52 53 public: 54 // getters next()55 emu_timer *next() const { return m_next; } machine()56 running_machine &machine() const noexcept { assert(m_machine != nullptr); return *m_machine; } enabled()57 bool enabled() const { return m_enabled; } param()58 int param() const { return m_param; } ptr()59 void *ptr() const { return m_ptr; } 60 61 // setters 62 bool enable(bool enable = true); set_param(int param)63 void set_param(int param) { m_param = param; } set_ptr(void * ptr)64 void set_ptr(void *ptr) { m_ptr = ptr; } 65 66 // control 67 void reset(const attotime &duration = attotime::never) { adjust(duration, m_param, m_period); } 68 void adjust(attotime start_delay, s32 param = 0, const attotime &periodicity = attotime::never); 69 70 // timing queries 71 attotime elapsed() const noexcept; 72 attotime remaining() const noexcept; start()73 attotime start() const { return m_start; } expire()74 attotime expire() const { return m_expire; } period()75 attotime period() const { return m_period; } 76 77 private: 78 // internal helpers 79 void register_save(); 80 void schedule_next_period(); 81 void dump() const; 82 static void device_timer_expired(emu_timer &timer, void *ptr, s32 param); 83 84 // internal state 85 running_machine * m_machine; // reference to the owning machine 86 emu_timer * m_next; // next timer in order in the list 87 emu_timer * m_prev; // previous timer in order in the list 88 timer_expired_delegate m_callback; // callback function 89 s32 m_param; // integer parameter 90 void * m_ptr; // pointer parameter 91 bool m_enabled; // is the timer enabled? 92 bool m_temporary; // is the timer temporary? 93 attotime m_period; // the repeat frequency of the timer 94 attotime m_start; // time when the timer was started 95 attotime m_expire; // time when the timer will expire 96 device_t * m_device; // for device timers, a pointer to the device 97 device_timer_id m_id; // for device timers, the ID of the timer 98 }; 99 100 101 // ======================> device_scheduler 102 103 class device_scheduler 104 { 105 friend class device_execute_interface; 106 friend class emu_timer; 107 108 public: 109 // construction/destruction 110 device_scheduler(running_machine &machine); 111 ~device_scheduler(); 112 113 // getters machine()114 running_machine &machine() const noexcept { return m_machine; } 115 attotime time() const noexcept; first_timer()116 emu_timer *first_timer() const { return m_timer_list; } currently_executing()117 device_execute_interface *currently_executing() const noexcept { return m_executing_device; } 118 bool can_save() const; 119 120 // execution 121 void timeslice(); 122 void abort_timeslice(); 123 void trigger(int trigid, const attotime &after = attotime::zero); 124 void boost_interleave(const attotime ×lice_time, const attotime &boost_duration); suspend_resume_changed()125 void suspend_resume_changed() { m_suspend_changes_pending = true; } 126 127 // timers, specified by callback/name 128 emu_timer *timer_alloc(timer_expired_delegate callback, void *ptr = nullptr); 129 void timer_set(const attotime &duration, timer_expired_delegate callback, int param = 0, void *ptr = nullptr); 130 void synchronize(timer_expired_delegate callback = timer_expired_delegate(), int param = 0, void *ptr = nullptr) { timer_set(attotime::zero, callback, param, ptr); } 131 132 // timers, specified by device/id; generally devices should use the device_t methods instead 133 emu_timer *timer_alloc(device_t &device, device_timer_id id = 0, void *ptr = nullptr); 134 void timer_set(const attotime &duration, device_t &device, device_timer_id id = 0, int param = 0, void *ptr = nullptr); 135 136 // debugging 137 void dump_timers() const; 138 139 // for emergencies only! 140 void eat_all_cycles(); 141 142 private: 143 // callbacks 144 void timed_trigger(void *ptr, s32 param); 145 void presave(); 146 void postload(); 147 148 // scheduling helpers 149 void compute_perfect_interleave(); 150 void rebuild_execute_list(); 151 void apply_suspend_changes(); 152 void add_scheduling_quantum(const attotime &quantum, const attotime &duration); 153 154 // timer helpers 155 emu_timer &timer_list_insert(emu_timer &timer); 156 emu_timer &timer_list_remove(emu_timer &timer); 157 void execute_timers(); 158 159 // internal state 160 running_machine & m_machine; // reference to our machine 161 device_execute_interface * m_executing_device; // pointer to currently executing device 162 device_execute_interface * m_execute_list; // list of devices to be executed 163 attotime m_basetime; // global basetime; everything moves forward from here 164 165 // list of active timers 166 emu_timer * m_timer_list; // head of the active list 167 fixed_allocator<emu_timer> m_timer_allocator; // allocator for timers 168 169 // other internal states 170 emu_timer * m_callback_timer; // pointer to the current callback timer 171 bool m_callback_timer_modified; // true if the current callback timer was modified 172 attotime m_callback_timer_expire_time; // the original expiration time 173 bool m_suspend_changes_pending; // suspend/resume changes are pending 174 175 // scheduling quanta 176 class quantum_slot 177 { 178 friend class simple_list<quantum_slot>; 179 180 public: next()181 quantum_slot *next() const { return m_next; } 182 183 quantum_slot * m_next; 184 attoseconds_t m_actual; // actual duration of the quantum 185 attoseconds_t m_requested; // duration of the requested quantum 186 attotime m_expire; // absolute expiration time of this quantum 187 }; 188 simple_list<quantum_slot> m_quantum_list; // list of active quanta 189 fixed_allocator<quantum_slot> m_quantum_allocator; // allocator for quanta 190 attoseconds_t m_quantum_minimum; // duration of minimum quantum 191 }; 192 193 194 #endif // MAME_EMU_SCHEDULE_H 195