Example #1
0
        // timer helpers

        //-------------------------------------------------
        //  timer_list_insert - insert a new timer into
        //  the list at the appropriate location
        //-------------------------------------------------
        public emu_timer timer_list_insert(emu_timer timer)
        {
            // disabled timers sort to the end
            attotime expire = timer.enabled() ? timer.expire() : attotime.never;

            // loop over the timer list
            emu_timer prevtimer = null;

            for (emu_timer curtimer = m_timer_list; curtimer != null; prevtimer = curtimer, curtimer = curtimer.next())
            {
                // if the current list entry expires after us, we should be inserted before it
                if (curtimer.expire() > expire)
                {
                    // link the new guy in before the current list entry
                    timer.m_prev = prevtimer;
                    timer.m_next = curtimer;

                    if (prevtimer != null)
                    {
                        prevtimer.m_next = timer;
                    }
                    else
                    {
                        m_timer_list = timer;
                    }

                    curtimer.m_prev = timer;

                    return(timer);
                }
            }

            // need to insert after the last one
            if (prevtimer != null)
            {
                prevtimer.m_next = timer;
            }
            else
            {
                m_timer_list = timer;
            }

            timer.m_prev = prevtimer;
            timer.m_next = null;

            return(timer);
        }
Example #2
0
        //-------------------------------------------------
        //  postload - after loading a save state
        //-------------------------------------------------
        void postload()
        {
            // remove all timers and make a private list of permanent ones
            simple_list <emu_timer> private_list = new simple_list <emu_timer>();

            while (m_timer_list != null)
            {
                emu_timer timer = m_timer_list;

                // temporary timers go away entirely (except our special never-expiring one)
                if (timer.m_temporary && !timer.expire().is_never())
                {
                    m_timer_allocator.reclaim(timer.release());
                }

                // permanent ones get added to our private list
                else
                {
                    private_list.append(timer_list_remove(timer));
                }
            }

            {
                // now re-insert them; this effectively re-sorts them by time
                emu_timer timer;
                while ((timer = private_list.detach_head()) != null)
                {
                    timer_list_insert(timer);
                }
            }

            m_suspend_changes_pending = true;
            rebuild_execute_list();

            // report the timer state after a log
            LOG("After resetting/reordering timers:\n");
#if VERBOSE
            dump_timers();
#endif
        }
Example #3
0
        // execution

        //-------------------------------------------------
        //  timeslice - execute all devices for a single
        //  timeslice
        //-------------------------------------------------
        public void timeslice()
        {
            bool call_debugger = (machine().debug_flags & DEBUG_FLAG_ENABLED) != 0;

            // build the execution list if we don't have one yet
            //if (UNEXPECTED(m_execute_list == null))
            if (m_execute_list == null)
            {
                rebuild_execute_list();
            }

            // if the current quantum has expired, find a new one
            while (m_basetime >= m_quantum_list.first().expire())
            {
                m_quantum_allocator.reclaim(m_quantum_list.detach_head());
            }

            // loop until we hit the next timer
            while (m_basetime < m_timer_list.expire())
            {
                // by default, assume our target is the end of the next quantum
                attotime target = m_basetime + new attotime(0, m_quantum_list.first().actual());

                // however, if the next timer is going to fire before then, override
                if (m_timer_list.expire() < target)
                {
                    target = m_timer_list.expire();
                }

                if (machine().video().frame_update_count() % 1000 == 0)
                {
                    //LOG(("------------------\n"));
                    LOG("device_scheduler.timeslice() - cpu_timeslice: target = {0}, m_timer_list.expire: {1}\n", target.as_string(), m_timer_list.expire().as_string());
                }

                // do we have pending suspension changes?
                if (m_suspend_changes_pending)
                {
                    apply_suspend_changes();
                }

                // loop over all CPUs
                for (device_execute_interface exec = m_execute_list; exec != null; exec = exec.m_nextexec)
                {
                    // only process if this CPU is executing or truly halted (not yielding)
                    // and if our target is later than the CPU's current time (coarse check)
                    if ((exec.m_suspend == 0 || exec.m_eatcycles > 0) && target.seconds() >= exec.m_localtime.seconds())  //if (EXPECTED((exec->m_suspend == 0 || exec->m_eatcycles) && target.seconds() >= exec->m_localtime.seconds()))
                    {
                        // compute how many attoseconds to execute this CPU
                        attoseconds_t delta = target.attoseconds() - exec.m_localtime.attoseconds();
                        if (delta < 0 && target.seconds() > exec.m_localtime.seconds())
                        {
                            delta += ATTOSECONDS_PER_SECOND;
                        }

                        assert(delta == (target - exec.m_localtime).as_attoseconds());

                        if (exec.m_attoseconds_per_cycle == 0)
                        {
                            exec.m_localtime = target;
                        }
                        // if we have enough for at least 1 cycle, do the math
                        else if (delta >= exec.m_attoseconds_per_cycle)
                        {
                            // compute how many cycles we want to execute
                            int ran = exec.m_cycles_running = (int)divu_64x32((u64)delta >> exec.m_divshift, (u32)exec.m_divisor);

                            if (machine().video().frame_update_count() % 1000 == 0)
                            {
                                LOG("device_scheduler.timeslice() - cpu '{0}': {1} ({2} cycles)\n", exec.device().tag(), delta, exec.m_cycles_running);
                            }

                            // if we're not suspended, actually execute
                            if (exec.m_suspend == 0)
                            {
                                g_profiler.start(exec.m_profiler);


                                // note that this global variable cycles_stolen can be modified
                                // via the call to cpu_execute
                                exec.m_cycles_stolen = 0;
                                m_executing_device   = exec;

                                exec.m_icountptr.i = exec.m_cycles_running;  // *exec->m_icountptr = exec->m_cycles_running;

                                if (!call_debugger)
                                {
                                    exec.run();
                                }
                                else
                                {
                                    exec.debugger_start_cpu_hook(target);
                                    exec.run();
                                    exec.debugger_stop_cpu_hook();
                                }

                                // adjust for any cycles we took back

                                //throw new emu_unimplemented();
#if false
                                assert(ran >= *exec->m_icountptr);
#endif

                                ran -= exec.m_icountptr.i;  //ran -= *exec->m_icountptr;

                                //throw new emu_unimplemented();
#if false
                                assert(ran >= exec->m_cycles_stolen);
#endif

                                ran -= exec.m_cycles_stolen;

                                g_profiler.stop();
                            }

                            // account for these cycles
                            exec.m_totalcycles += (u64)ran;

                            // update the local time for this CPU
                            attotime deltatime;
                            if (ran < exec.m_cycles_per_second)
                            {
                                deltatime = new attotime(0, exec.m_attoseconds_per_cycle * ran);
                            }
                            else
                            {
                                u32 remainder;
                                s32 secs = (s32)divu_64x32_rem((u64)ran, exec.m_cycles_per_second, out remainder);
                                deltatime = new attotime(secs, remainder * exec.m_attoseconds_per_cycle);
                            }

                            assert(deltatime >= attotime.zero);
                            exec.m_localtime += deltatime;

                            if (machine().video().frame_update_count() % 100 == 0)
                            {
                                LOG("device_scheduler.timeslice() - {0} ran, {1} total, time = {2}\n", ran, exec.m_totalcycles, exec.m_localtime.as_string());
                            }

                            // if the new local CPU time is less than our target, move the target up, but not before the base
                            if (exec.m_localtime < target)
                            {
                                target = std.max(exec.m_localtime, m_basetime);

                                if (machine().video().frame_update_count() % 1000 == 0)
                                {
                                    LOG("device_scheduler.timeslice() - (new target)\n");
                                }
                            }
                        }
                    }
                }

                m_executing_device = null;

                // update the base time
                m_basetime = target;
            }

            // execute timers
            execute_timers();
        }
Example #4
0
        //-------------------------------------------------
        //  execute_timers - execute timers that are due
        //-------------------------------------------------
        void execute_timers()
        {
            if (machine().video().frame_update_count() % 400 == 0)
            {
                LOG("execute_timers: new={0} head->expire={1}\n", m_basetime.as_string(), m_timer_list.expire().as_string());
            }

            // now process any timers that are overdue
            while (m_timer_list.expire() <= m_basetime)
            {
                // if this is a one-shot timer, disable it now
                emu_timer timer       = m_timer_list;
                bool      was_enabled = timer.enabled();
                if (timer.m_period.is_zero() || timer.m_period.is_never())
                {
                    timer.m_enabled = false;
                }

                // set the global state of which callback we're in
                m_callback_timer_modified    = false;
                m_callback_timer             = timer;
                m_callback_timer_expire_time = timer.expire();

                // call the callback
                if (was_enabled)
                {
                    g_profiler.start(profile_type.PROFILER_TIMER_CALLBACK);

                    if (timer.m_callback != null)
                    {
                        if (timer.m_device != null)
                        {
                            LOG("execute_timers: expired: {0} timer device {1} timer {2}\n", timer.expire().attoseconds(), timer.m_device.tag(), timer.m_id);
                        }
                        else
                        {
                            LOG("execute_timers: expired: {0} timer callback {1}\n", timer.expire().attoseconds(), timer.m_callback.ToString());
                        }

                        timer.m_callback(timer.m_ptr, timer.m_param);
                    }

                    g_profiler.stop();
                }

                // reset or remove the timer, but only if it wasn't modified during the callback
                if (!m_callback_timer_modified)
                {
                    // if the timer is temporary, remove it now
                    if (timer.m_temporary)
                    {
                        m_timer_allocator.reclaim(timer.release());
                    }

                    // otherwise, reschedule it
                    else
                    {
                        timer.schedule_next_period();
                    }
                }
            }

            // clear the callback timer global
            m_callback_timer = null;
        }