// 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(); }
//------------------------------------------------- // first_dirty_rect -- return the first dirty // rectangle in the list //------------------------------------------------- public sparse_dirty_rect first_dirty_rect(rectangle cliprect) { // if what we have is valid, just return it again if (m_rect_list_bounds == cliprect) { return(m_rect_list.empty() ? null : m_rect_list.first()); } // reclaim the dirty list and start over m_rect_allocator.reclaim_all(m_rect_list); // compute dirty space rectangle coordinates int sx = cliprect.min_x >> m_granularity; int ex = cliprect.max_x >> m_granularity; int sy = cliprect.min_y >> m_granularity; int ey = cliprect.max_y >> m_granularity; int tilesize = 1 << m_granularity; // loop over all grid rows that intersect our cliprect for (int y = sy; y <= ey; y++) { PointerU8 dirtybase = m_bitmap.pix(y); //uint8_t *dirtybase = &m_bitmap.pix(y); sparse_dirty_rect currect = null; // loop over all grid columns that intersect our cliprect for (int x = sx; x <= ex; x++) { // if this tile is not dirty, end our current run and continue if (dirtybase[x] == 0) { if (currect != null) { currect.m_rect &= cliprect; //*currect &= cliprect; } currect = null; continue; } // if we can't add to an existing rect, create a new one if (currect == null) { // allocate a new rect and add it to the list currect = m_rect_list.append(m_rect_allocator.alloc()); // make a rect describing this grid square currect.m_rect.min_x = x << m_granularity; currect.m_rect.max_x = currect.m_rect.min_x + tilesize - 1; currect.m_rect.min_y = y << m_granularity; currect.m_rect.max_y = currect.m_rect.min_y + tilesize - 1; } // if we can add to the previous rect, just expand its width else { currect.m_rect.max_x += tilesize; } } // clip the last rect to the cliprect if (currect != null) { currect.m_rect &= cliprect; } } // mark the list as valid m_rect_list_bounds = cliprect; return(m_rect_list.empty() ? null : m_rect_list.first()); }