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 &timeslice_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