Esempio n. 1
0
        //void trigger(int trigid, const attotime &after = attotime::zero);


        //-------------------------------------------------
        //  boost_interleave - temporarily boosts the
        //  interleave factor
        //-------------------------------------------------
        public void boost_interleave(attotime timeslice_time, attotime boost_duration)
        {
            // ignore timeslices > 1 second
            if (timeslice_time.seconds() > 0)
            {
                return;
            }

            add_scheduling_quantum(timeslice_time, boost_duration);
        }
Esempio n. 2
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.prev_set(curtimer.prev());
                    timer.next_set(curtimer);

                    if (curtimer.prev() != null)
                    {
                        curtimer.prev().next_set(timer);
                    }
                    else
                    {
                        m_timer_list = timer;
                    }

                    curtimer.prev_set(timer);

                    return(timer);
                }
            }

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

            timer.prev_set(prevtimer);
            timer.next_set(null);

            return(timer);
        }
Esempio n. 3
0
        attoseconds_t m_quantum_minimum;                                                           // duration of minimum quantum


        // construction/destruction

        //-------------------------------------------------
        //  device_scheduler - constructor
        //-------------------------------------------------
        public device_scheduler(running_machine machine)
        {
            m_machine  = machine;
            m_basetime = attotime.zero;
            m_callback_timer_expire_time = attotime.zero;
            m_suspend_changes_pending    = true;
            m_quantum_minimum            = attotime.ATTOSECONDS_IN_NSEC(1) / 1000;

            // append a single never-expiring timer so there is always one in the list
            //m_timer_list = m_timer_allocator.alloc().init(machine, null, null, true);
            //m_timer_list.adjust(attotime.never);

            // register global states
            machine.save().save_item(m_basetime, "m_basetime");
            machine.save().register_presave(presave);
            machine.save().register_postload(postload);
        }
Esempio n. 4
0
        //-------------------------------------------------
        //  add_scheduling_quantum - add a scheduling
        //  quantum; the smallest active one is the one
        //  that is in use
        //-------------------------------------------------
        void add_scheduling_quantum(attotime quantum, attotime duration)
        {
            assert(quantum.seconds() == 0);

            attotime      curtime       = time();
            attotime      expire        = curtime + duration;
            attoseconds_t quantum_attos = quantum.attoseconds();

            // figure out where to insert ourselves, expiring any quanta that are out-of-date
            quantum_slot insert_after = null;
            quantum_slot next;

            for (quantum_slot quant = m_quantum_list.first(); quant != null; quant = next)
            {
                // if this quantum is expired, nuke it
                next = quant.next();
                if (curtime >= quant.expire())
                {
                    m_quantum_allocator.reclaim(m_quantum_list.detach(quant));
                }

                // if this quantum is shorter than us, we need to be inserted afterwards
                else if (quant.requested() <= quantum_attos)
                {
                    insert_after = quant;
                }
            }

            // if we found an exact match, just take the maximum expiry time
            if (insert_after != null && insert_after.requested() == quantum_attos)
            {
                insert_after.expire_set(attotime.Max(insert_after.expire(), expire));
            }

            // otherwise, allocate a new quantum and insert it after the one we picked
            else
            {
                quantum_slot quant = m_quantum_allocator.alloc();
                quant.requested_set(quantum_attos);
                quant.actual_set(Math.Max(quantum_attos, m_quantum_minimum));
                quant.expire_set(expire);
                m_quantum_list.insert_after(quant, insert_after);
            }
        }
Esempio n. 5
0
        //-------------------------------------------------
        //  rebuild_execute_list - rebuild the list of
        //  executing CPUs, moving suspended CPUs to the
        //  end
        //-------------------------------------------------
        void rebuild_execute_list()
        {
            // if we haven't yet set a scheduling quantum, do it now
            if (m_quantum_list.empty())
            {
                // set the core scheduling quantum
                attotime min_quantum = machine().config().minimum_quantum;

                // if none specified default to 60Hz
                if (min_quantum.is_zero())
                {
                    min_quantum = attotime.from_hz(60);
                }

                // if the configuration specifies a device to make perfect, pick that as the minimum
                if (!machine().config().perfect_cpu_quantum().empty())
                {
                    device_t device = machine().root_device().subdevice(machine().config().perfect_cpu_quantum().c_str());
                    if (device == null)
                    {
                        fatalerror("Device '{0}' specified for perfect interleave is not present!\n", machine().config().perfect_cpu_quantum());
                    }

                    device_execute_interface exec;
                    if (!device.interface_(out exec))
                    {
                        fatalerror("Device '{0}' specified for perfect interleave is not an executing device!\n", machine().config().perfect_cpu_quantum());
                    }

                    min_quantum = attotime.Min(new attotime(0, exec.minimum_quantum()), min_quantum);
                }

                // make sure it's no higher than 60Hz
                min_quantum = attotime.Min(min_quantum, attotime.from_hz(60));

                // inform the timer system of our decision
                add_scheduling_quantum(min_quantum, attotime.never);
            }


            // start with an empty list
            //device_execute_interface **active_tailptr = &m_execute_list;
            //*active_tailptr = NULL;

            // also make an empty list of suspended devices
            //device_execute_interface *suspend_list = NULL;
            //device_execute_interface **suspend_tailptr = &suspend_list;

            List <device_execute_interface> active_list  = new List <device_execute_interface>();
            List <device_execute_interface> suspend_list = new List <device_execute_interface>();


            // iterate over all devices
            foreach (device_execute_interface exec in new execute_interface_iterator(machine().root_device()))
            {
                // append to the appropriate list
                exec.nextexec = null;
                if (exec.suspend_ == 0)
                {
                    //*active_tailptr = exec;
                    //active_tailptr = &exec.m_nextexec;
                    active_list.Add(exec);
                }
                else
                {
                    //*suspend_tailptr = exec;
                    //suspend_tailptr = &exec.m_nextexec;
                    suspend_list.Add(exec);
                }
            }


            // append the suspend list to the end of the active list
            //*active_tailptr = suspend_list;
            active_list.AddRange(suspend_list);
            if (active_list.Count > 0)
            {
                m_execute_list = active_list[0];

                for (int i = 0; i < active_list.Count; i++)
                {
                    if (i < active_list.Count - 1)
                    {
                        active_list[i].nextexec = active_list[i + 1];
                    }
                    else
                    {
                        active_list[i].nextexec = null;
                    }
                }
            }
        }
Esempio n. 6
0
 //-------------------------------------------------
 //  timer_set - allocate an anonymous device timer
 //  and set it to go off after the given amount of
 //  time
 //-------------------------------------------------
 public void timer_set(attotime duration, device_t device, device_timer_id id = 0, int param = 0, object ptr = null)
 {
     m_timer_allocator.alloc().init(device, id, ptr, true).adjust(duration, param);
 }
Esempio n. 7
0
 //-------------------------------------------------
 //  timer_set - allocate an anonymous non-device
 //  timer and set it to go off after the given
 //  amount of time
 //-------------------------------------------------
 public void timer_set(attotime duration, timer_expired_delegate callback, int param = 0, object ptr = null)
 {
     m_timer_allocator.alloc().init(machine(), callback, ptr, true).adjust(duration, param);
 }
Esempio n. 8
0
        // execution

        //-------------------------------------------------
        //  timeslice - execute all devices for a single
        //  timeslice
        //-------------------------------------------------
        public void timeslice()
        {
            bool call_debugger = (machine().debug_flags_get & machine_global.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.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 (EXPECTED((exec.m_suspend == 0 || exec.m_eatcycles) && target.seconds >= exec.m_localtime.seconds))
                    if ((exec.suspend_ == 0 || exec.eatcycles > 0) && target.seconds() >= exec.localtime.seconds())
                    {
                        // compute how many attoseconds to execute this CPU
                        attoseconds_t delta = target.attoseconds() - exec.localtime.attoseconds();
                        if (delta < 0 && target.seconds() > exec.localtime.seconds())
                        {
                            delta += attotime.ATTOSECONDS_PER_SECOND;
                        }

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

                        if (exec.attoseconds_per_cycle == 0)
                        {
                            exec.localtime = target;
                        }
                        // if we have enough for at least 1 cycle, do the math
                        else if (delta >= exec.attoseconds_per_cycle)
                        {
                            // compute how many cycles we want to execute
                            int ran = exec.cycles_running = (int)divu_64x32((UInt64)delta >> exec.divshift, (UInt32)exec.divisor);

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

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


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

                                exec.icount_set(exec.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
                                /*assert(ran >= *exec->m_icountptr);*/
                                ran -= exec.icountptrRef.i;

                                /*assert(ran >= exec->m_cycles_stolen);*/
                                ran -= exec.cycles_stolen;


                                profiler_global.g_profiler.stop();
                            }

                            // account for these cycles
                            exec.totalcycles += (UInt64)ran;

                            // update the local time for this CPU
                            attotime deltatime;
                            if (ran < exec.cycles_per_second)
                            {
                                deltatime = new attotime(0, exec.attoseconds_per_cycle * ran);
                            }
                            else
                            {
                                UInt32 remainder;
                                int    secs = (int)divu_64x32_rem((UInt64)ran, exec.cycles_per_second, out remainder);
                                deltatime = new attotime(secs, remainder * exec.attoseconds_per_cycle);
                            }

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

                            if (machine().video().frame_update_count() % 100 == 0)
                            {
                                LOG("device_scheduler.timeslice() - {0} ran, {1} total, time = {2}\n", ran, exec.totalcycles, exec.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.localtime < target)
                            {
                                target = attotime.Max(exec.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();
        }
Esempio n. 9
0
 public void expire_set(attotime value)
 {
     m_expire = value;
 }
Esempio n. 10
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.period().is_zero() || timer.period().is_never())
                {
                    timer.enabled_set(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)
                {
                    profiler_global.g_profiler.start(profile_type.PROFILER_TIMER_CALLBACK);


                    if (timer.device() != null)
                    {
                        if (machine().video().frame_update_count() % 400 == 0)
                        {
                            LOG("execute_timers: timer device {0} timer {1}\n", timer.device().tag(), timer.id());
                        }

                        timer.device().timer_expired(timer, timer.id(), timer.param(), timer.ptr());
                    }
                    else if (timer.callback() != null)
                    {
                        if (machine().video().frame_update_count() % 400 == 0)
                        {
                            LOG("execute_timers: timer callback {0}\n", timer.callback());
                        }

                        timer.callback()(timer.ptr(), timer.param());
                    }


                    profiler_global.g_profiler.stop();
                }

                // clear the callback timer global
                m_callback_timer = null;

                // 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.temporary())
                    {
                        m_timer_allocator.reclaim(timer.release());
                    }

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