summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/emu/schedule.h
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/emu/schedule.h')
-rw-r--r--trunk/src/emu/schedule.h243
1 files changed, 243 insertions, 0 deletions
diff --git a/trunk/src/emu/schedule.h b/trunk/src/emu/schedule.h
new file mode 100644
index 00000000000..6ef60ce0f9c
--- /dev/null
+++ b/trunk/src/emu/schedule.h
@@ -0,0 +1,243 @@
+/***************************************************************************
+
+ schedule.h
+
+ Core device execution and scheduling engine.
+
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __EMU_H__
+#error Dont include this file directly; include emu.h instead.
+#endif
+
+#ifndef __SCHEDULE_H__
+#define __SCHEDULE_H__
+
+
+//**************************************************************************
+// MACROS
+//**************************************************************************
+
+// macro for the RC time constant on a 74LS123 with C > 1000pF
+// R is in ohms, C is in farads
+#define TIME_OF_74LS123(r,c) (0.45 * (double)(r) * (double)(c))
+
+// macros for the RC time constant on a 555 timer IC
+// R is in ohms, C is in farads
+#define PERIOD_OF_555_MONOSTABLE_NSEC(r,c) ((attoseconds_t)(1100000000 * (double)(r) * (double)(c)))
+#define PERIOD_OF_555_ASTABLE_NSEC(r1,r2,c) ((attoseconds_t)( 693000000 * ((double)(r1) + 2.0 * (double)(r2)) * (double)(c)))
+#define PERIOD_OF_555_MONOSTABLE(r,c) attotime::from_nsec(PERIOD_OF_555_MONOSTABLE_NSEC(r,c))
+#define PERIOD_OF_555_ASTABLE(r1,r2,c) attotime::from_nsec(PERIOD_OF_555_ASTABLE_NSEC(r1,r2,c))
+
+#define TIMER_CALLBACK(name) void name(running_machine &machine, void *ptr, int param)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// timer callbacks look like this
+typedef delegate<void (void *, INT32)> timer_expired_delegate;
+
+// old-skool callbacks are like this
+typedef void (*timer_expired_func)(running_machine &machine, void *ptr, INT32 param);
+
+
+// ======================> emu_timer
+
+class emu_timer
+{
+ friend class device_scheduler;
+ friend class simple_list<emu_timer>;
+ friend class fixed_allocator<emu_timer>;
+ friend class resource_pool_object<emu_timer>;
+
+ // construction/destruction
+ emu_timer();
+ ~emu_timer();
+
+ // allocation and re-use
+ emu_timer &init(running_machine &machine, timer_expired_delegate callback, void *ptr, bool temporary);
+ emu_timer &init(device_t &device, device_timer_id id, void *ptr, bool temporary);
+ emu_timer &release();
+
+public:
+ // getters
+ emu_timer *next() const { return m_next; }
+ running_machine &machine() const { assert(m_machine != NULL); return *m_machine; }
+ bool enabled() const { return m_enabled; }
+ int param() const { return m_param; }
+ void *ptr() const { return m_ptr; }
+
+ // setters
+ bool enable(bool enable = true);
+ void set_param(int param) { m_param = param; }
+ void set_ptr(void *ptr) { m_ptr = ptr; }
+
+ // control
+ void reset(attotime duration = attotime::never) { adjust(duration, m_param, m_period); }
+ void adjust(attotime duration, INT32 param = 0, attotime periodicity = attotime::never);
+
+ // timing queries
+ attotime elapsed() const;
+ attotime remaining() const;
+ attotime start() const { return m_start; }
+ attotime expire() const { return m_expire; }
+
+private:
+ // internal helpers
+ void register_save();
+ void schedule_next_period();
+ void dump() const;
+
+ // internal state
+ running_machine * m_machine; // reference to the owning machine
+ emu_timer * m_next; // next timer in order in the list
+ emu_timer * m_prev; // previous timer in order in the list
+ timer_expired_delegate m_callback; // callback function
+ INT32 m_param; // integer parameter
+ void * m_ptr; // pointer parameter
+ bool m_enabled; // is the timer enabled?
+ bool m_temporary; // is the timer temporary?
+ attotime m_period; // the repeat frequency of the timer
+ attotime m_start; // time when the timer was started
+ attotime m_expire; // time when the timer will expire
+ device_t * m_device; // for device timers, a pointer to the device
+ device_timer_id m_id; // for device timers, the ID of the timer
+};
+
+
+// ======================> device_scheduler
+
+class device_scheduler
+{
+ friend class device_execute_interface;
+ friend class emu_timer;
+
+public:
+ // construction/destruction
+ device_scheduler(running_machine &machine);
+ ~device_scheduler();
+
+ // getters
+ running_machine &machine() const { return m_machine; }
+ attotime time() const;
+ emu_timer *first_timer() const { return m_timer_list; }
+ device_execute_interface *currently_executing() const { return m_executing_device; }
+ bool can_save() const;
+
+ // execution
+ void timeslice();
+ void abort_timeslice();
+ void trigger(int trigid, attotime after = attotime::zero);
+ void boost_interleave(attotime timeslice_time, attotime boost_duration);
+// void make_active() { m_cothread.make_active(); }
+
+ // timers, specified by callback/name
+ emu_timer *timer_alloc(timer_expired_delegate callback, void *ptr = NULL);
+ void timer_set(attotime duration, timer_expired_delegate callback, int param = 0, void *ptr = NULL);
+ void timer_pulse(attotime period, timer_expired_delegate callback, int param = 0, void *ptr = NULL);
+ void synchronize(timer_expired_delegate callback = timer_expired_delegate(), int param = 0, void *ptr = NULL) { timer_set(attotime::zero, callback, param, ptr); }
+
+ // timers with old-skool callbacks
+ emu_timer *timer_alloc(timer_expired_func callback, const char *name, void *ptr = NULL) { return timer_alloc(timer_expired_delegate(callback, name, &machine()), ptr); }
+ void timer_set(attotime duration, timer_expired_func callback, const char *name, int param = 0, void *ptr = NULL) { timer_set(duration, timer_expired_delegate(callback, name, &machine()), param, ptr); }
+ void timer_pulse(attotime period, timer_expired_func callback, const char *name, int param = 0, void *ptr = NULL) { timer_pulse(period, timer_expired_delegate(callback, name, &machine()), param, ptr); }
+ void synchronize(timer_expired_func callback, const char *name = NULL, int param = 0, void *ptr = NULL) { timer_set(attotime::zero, callback, name, param, ptr); }
+
+ // timers, specified by device/id; generally devices should use the device_t methods instead
+ emu_timer *timer_alloc(device_t &device, device_timer_id id = 0, void *ptr = NULL);
+ void timer_set(attotime duration, device_t &device, device_timer_id id = 0, int param = 0, void *ptr = NULL);
+
+ // debugging
+ void dump_timers() const;
+
+ // for emergencies only!
+ void eat_all_cycles();
+
+private:
+ // callbacks
+ void timed_trigger(void *ptr, INT32 param);
+ void presave();
+ void postload();
+
+ // scheduling helpers
+ void compute_perfect_interleave();
+ void rebuild_execute_list();
+ void add_scheduling_quantum(attotime quantum, attotime duration);
+
+ // timer helpers
+ emu_timer &timer_list_insert(emu_timer &timer);
+ emu_timer &timer_list_remove(emu_timer &timer);
+ void execute_timers();
+
+ // internal state
+ running_machine & m_machine; // reference to our machine
+ device_execute_interface * m_executing_device; // pointer to currently executing device
+ device_execute_interface * m_execute_list; // list of devices to be executed
+ attotime m_basetime; // global basetime; everything moves forward from here
+// cothread m_cothread; // core scheduler thread
+
+ // list of active timers
+ emu_timer * m_timer_list; // head of the active list
+ fixed_allocator<emu_timer> m_timer_allocator; // allocator for timers
+
+ // other internal states
+ emu_timer * m_callback_timer; // pointer to the current callback timer
+ bool m_callback_timer_modified; // true if the current callback timer was modified
+ attotime m_callback_timer_expire_time; // the original expiration time
+
+ // scheduling quanta
+ class quantum_slot
+ {
+ friend class simple_list<quantum_slot>;
+
+ public:
+ quantum_slot *next() const { return m_next; }
+
+ quantum_slot * m_next;
+ attoseconds_t m_actual; // actual duration of the quantum
+ attoseconds_t m_requested; // duration of the requested quantum
+ attotime m_expire; // absolute expiration time of this quantum
+ };
+ simple_list<quantum_slot> m_quantum_list; // list of active quanta
+ fixed_allocator<quantum_slot> m_quantum_allocator; // allocator for quanta
+ attoseconds_t m_quantum_minimum; // duration of minimum quantum
+};
+
+
+#endif // __SCHEDULE_H__ */