Пример #1
0
        public void adjust(attotime start_delay, int param, attotime period)  //void adjust(attotime start_delay, s32 param = 0, const attotime &periodicity = attotime::never);
        {
            // if this is the callback timer, mark it modified
            device_scheduler scheduler = machine().scheduler();

            if (scheduler.callback_timer() == this)
            {
                scheduler.callback_timer_modified_set(true);
            }

            // compute the time of the next firing and insert into the list
            m_param   = param;
            m_enabled = true;

            // clamp negative times to 0
            if (start_delay.seconds() < 0)
            {
                start_delay = attotime.zero;
            }

            // set the start and expire times
            m_start  = scheduler.time();
            m_expire = m_start + start_delay;
            m_period = period;

            // remove and re-insert the timer in its new order
            scheduler.timer_list_remove(this);
            scheduler.timer_list_insert(this);

            // if this was inserted as the head, abort the current timeslice and resync
            if (this == scheduler.first_timer())
            {
                scheduler.abort_timeslice();
            }
        }
Пример #2
0
        //-------------------------------------------------
        //  update - force a stream to update to
        //  the current emulated time
        //-------------------------------------------------
        public void update()
        {
            if (m_attoseconds_per_sample == 0)
            {
                return;
            }

            // determine the number of samples since the start of this second
            attotime time             = m_device.machine().time();
            int      update_sampindex = (int)(time.attoseconds() / m_attoseconds_per_sample);

            // if we're ahead of the last update, then adjust upwards
            attotime last_update = m_device.machine().sound().last_update();

            if (time.seconds() > last_update.seconds())
            {
                assert(time.seconds() == last_update.seconds() + 1);
                update_sampindex += (int)m_sample_rate;
            }

            // if we're behind the last update, then adjust downwards
            if (time.seconds() < last_update.seconds())
            {
                assert(time.seconds() == last_update.seconds() - 1);
                update_sampindex -= (int)m_sample_rate;
            }

            if (update_sampindex <= m_output_sampindex)
            {
                return;
            }

            // generate samples to get us up to the appropriate time
            profiler_global.g_profiler.start(profile_type.PROFILER_SOUND);

            //throw new emu_unimplemented();
#if false
            osdcomm_global.assert(m_output_sampindex - m_output_base_sampindex >= 0);
            osdcomm_global.assert(update_sampindex - m_output_base_sampindex <= m_output_bufalloc);
#endif

            generate_samples(update_sampindex - m_output_sampindex);
            profiler_global.g_profiler.stop();

            // remember this info for next time
            m_output_sampindex = update_sampindex;
        }
Пример #3
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);
        }
Пример #4
0
        // internal helpers

        //-------------------------------------------------
        //  video_exit - close down the video system
        //-------------------------------------------------
        void exit(running_machine machine_)
        {
            // stop recording any movie
            m_movie_recordings.clear();

            // free the snapshot target
            machine().render().target_free(m_snap_target);
            m_snap_bitmap.reset();

            // print a final result if we have at least 2 seconds' worth of data
            if (!emulator_info.standalone() && m_overall_emutime.seconds() >= 1)
            {
                osd_ticks_t tps             = m_osdcore.osd_ticks_per_second();
                double      final_real_time = (double)m_overall_real_seconds + (double)m_overall_real_ticks / (double)tps;
                double      final_emu_time  = m_overall_emutime.as_double();
                osd_printf_info("Average speed: {0}%% ({1} seconds)\n", 100 * final_emu_time / final_real_time, (m_overall_emutime + new attotime(0, ATTOSECONDS_PER_SECOND / 2)).seconds());  // %.2f%% (%d seconds)\n
            }
        }
Пример #5
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(std.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(std.max(quantum_attos, m_quantum_minimum));
                quant.expire_set(expire);
                m_quantum_list.insert_after(quant, insert_after);
            }
        }
Пример #6
0
        //-------------------------------------------------
        //  update - mix everything down to its final form
        //  and send it to the OSD layer
        //-------------------------------------------------
        void update(object o = null, s32 param = 0)  // (void *ptr = nullptr, s32 param = 0);
        {
            sound_global.VPRINTF("sound_update\n");

            profiler_global.g_profiler.start(profile_type.PROFILER_SOUND);


            // force all the speaker streams to generate the proper number of samples
            int samples_this_update = 0;

            foreach (speaker_device speaker in new speaker_device_iterator(machine().root_device()))
            {
                speaker.mix(m_leftmix, m_rightmix, ref samples_this_update, (m_muted & MUTE_REASON_SYSTEM) != 0);
            }

            // now downmix the final result
            u32 finalmix_step          = (UInt32)machine().video().speed_factor();
            u32 finalmix_offset        = 0;
            ListPointer <s16> finalmix = new ListPointer <s16>(m_finalmix);  //s16 *finalmix = &m_finalmix[0];
            int sample;

            for (sample = (int)m_finalmix_leftover; sample < samples_this_update * 1000; sample += (int)finalmix_step)
            {
                int sampindex = sample / 1000;

                // clamp the left side
                int samp = m_leftmix[sampindex];
                if (samp < -32768)
                {
                    samp = -32768;
                }
                else if (samp > 32767)
                {
                    samp = 32767;
                }

                finalmix[finalmix_offset++] = (Int16)samp;

                // clamp the right side
                samp = m_rightmix[sampindex];
                if (samp < -32768)
                {
                    samp = -32768;
                }
                else if (samp > 32767)
                {
                    samp = 32767;
                }

                finalmix[finalmix_offset++] = (Int16)samp;
            }

            m_finalmix_leftover = (UInt32)(sample - samples_this_update * 1000);

            // play the result
            if (finalmix_offset > 0)
            {
                if (m_nosound_mode == 0)
                {
                    machine().osd().update_audio_stream(finalmix, (int)(finalmix_offset / 2));
                }

                machine().osd().add_audio_to_recording(finalmix, (int)finalmix_offset / 2);
                machine().video().add_sound_to_recording(finalmix, (int)(finalmix_offset / 2));

                if (m_wavfile != null)
                {
                    wavwrite_global.wav_add_data_16(m_wavfile, finalmix, (int)finalmix_offset);
                }
            }

            // see if we ticked over to the next second
            attotime curtime     = machine().time();
            bool     second_tick = false;

            if (curtime.seconds() != m_last_update.seconds())
            {
                assert(curtime.seconds() == m_last_update.seconds() + 1);
                second_tick = true;
            }

            // iterate over all the streams and update them
            foreach (var stream in m_stream_list)
            {
                stream.update_with_accounting(second_tick);
            }

            // remember the update time
            m_last_update = curtime;

            // update sample rates if they have changed
            foreach (var stream in m_stream_list)
            {
                stream.apply_sample_rate_changes();
            }


            profiler_global.g_profiler.stop();
        }
Пример #7
0
        //-------------------------------------------------
        //  recompute_speed - recompute the current
        //  overall speed; we assume this is called only
        //  if we did not skip a frame
        //-------------------------------------------------
        void recompute_speed(attotime emutime)
        {
            // if we don't have a starting time yet, or if we're paused, reset our starting point
            if (m_speed_last_realtime == 0 || machine().paused())
            {
                m_speed_last_realtime = m_osdcore.osd_ticks();
                m_speed_last_emutime  = emutime;
            }

            // if it has been more than the update interval, update the time
            attotime delta_emutime = emutime - m_speed_last_emutime;

            if (delta_emutime > new attotime(0, ATTOSECONDS_PER_SPEED_UPDATE))
            {
                // convert from ticks to attoseconds
                osd_ticks_t realtime       = m_osdcore.osd_ticks();
                osd_ticks_t delta_realtime = realtime - m_speed_last_realtime;
                osd_ticks_t tps            = m_osdcore.osd_ticks_per_second();
                m_speed_percent = delta_emutime.as_double() * (double)tps / (double)delta_realtime;

                // remember the last times
                m_speed_last_realtime = realtime;
                m_speed_last_emutime  = emutime;

                // if we're throttled, this time period counts for overall speed; otherwise, we reset the counter
                if (!m_fastforward)
                {
                    m_overall_valid_counter++;
                }
                else
                {
                    m_overall_valid_counter = 0;
                }

                // if we've had at least 4 consecutive valid periods, accumulate stats
                if (m_overall_valid_counter >= 4)
                {
                    m_overall_real_ticks += delta_realtime;
                    while (m_overall_real_ticks >= tps)
                    {
                        m_overall_real_ticks -= tps;
                        m_overall_real_seconds++;
                    }
                    m_overall_emutime += delta_emutime;
                }
            }

            // if we're past the "time-to-execute" requested, signal an exit
            if (m_seconds_to_run != 0 && emutime.seconds() >= m_seconds_to_run)
            {
                // create a final screenshot
                emu_file            file   = new emu_file(machine().options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
                std.error_condition filerr = open_next(file, "png");
                if (!filerr)
                {
                    save_snapshot(null, file);
                }

                file.close();

                //printf("Scheduled exit at %f\n", emutime.as_double());

                // schedule our demise
                machine().schedule_exit();
            }
        }
Пример #8
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();
        }