/*************************************************************************** event.cpp - Event schdeduler (based on alarm from Vice) ------------------- begin : Wed May 9 2001 copyright : (C) 2001 by Simon White email : s_a_white@email.com ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /*************************************************************************** * $Log: event.cpp,v $ * Revision 1.7 2002/11/21 19:55:38 s_a_white * We now jump to next event directly instead on clocking by a number of * cycles. * * Revision 1.6 2002/07/17 19:20:03 s_a_white * More efficient event handling code. * * Revision 1.5 2001/10/02 18:24:09 s_a_white * Updated to support safe scheduler interface. * * Revision 1.4 2001/09/17 19:00:28 s_a_white * Constructor moved out of line. * * Revision 1.3 2001/09/15 13:03:50 s_a_white * timeWarp now zeros m_eventClk instead of m_pendingEventClk which * fixes a inifinite loop problem when driving libsidplay1. * ***************************************************************************/ #include #include "event.h" #define EVENT_TIMEWARP_COUNT 0x0FFFFF EventScheduler::EventScheduler (const char * const name) :m_name(name), m_pendingEventCount(0), m_timeWarp(this) { memset (&m_pendingEvents, 0, sizeof (Event)); m_pendingEvents.m_next = &m_pendingEvents; m_pendingEvents.m_prev = &m_pendingEvents; reset (); } // Usefull to prevent clock overflowing void EventScheduler::timeWarp () { Event *e = &m_pendingEvents; uint count = m_pendingEventCount; while (count--) { // Reduce all event clocks and clip them // so none go negative event_clock_t clk; e = e->m_next; clk = e->m_clk; e->m_clk = 0; if (clk >= m_eventClk) e->m_clk = clk - m_eventClk; } m_eventClk = 0; // Re-schedule the next timeWarp schedule (&m_timeWarp, EVENT_TIMEWARP_COUNT); } void EventScheduler::reset (void) { // Remove all events Event *e = &m_pendingEvents; uint count = m_pendingEventCount; while (count--) { e = e->m_next; e->m_pending = false; } m_pendingEvents.m_next = &m_pendingEvents; m_pendingEvents.m_prev = &m_pendingEvents; m_pendingEventClk = m_eventClk = m_schedClk = 0; m_pendingEventCount = 0; timeWarp (); } // Add event to ordered pending queue void EventScheduler::schedule (Event *event, event_clock_t cycles) { uint clk = m_eventClk + cycles; if (event->m_pending) cancelPending (*event); event->m_pending = true; event->m_clk = clk; { // Now put in the correct place so we don't need to keep // searching the list later. Event *e = m_pendingEvents.m_next; uint count = m_pendingEventCount; while (count-- && (e->m_clk <= clk)) e = e->m_next; event->m_next = e; event->m_prev = e->m_prev; e->m_prev->m_next = event; e->m_prev = event; m_pendingEventClk = m_pendingEvents.m_next->m_clk; m_pendingEventCount++; } } // Cancel a pending event void EventScheduler::cancel (Event *event) { if (event->m_pending) cancelPending (*event); }