void bx_pit_c::handle_timer() { Bit64u my_time_usec = bx_virt_timer.time_usec(); Bit64u time_passed = my_time_usec-BX_PIT_THIS s.last_usec; Bit32u time_passed32 = (Bit32u)time_passed; BX_DEBUG(("entering timer handler")); if(time_passed32) { periodic(time_passed32); } BX_PIT_THIS s.last_usec = BX_PIT_THIS s.last_usec + time_passed; if (time_passed || (BX_PIT_THIS s.last_next_event_time != BX_PIT_THIS s.timer.get_next_event_time())) { BX_DEBUG(("RESETting timer")); bx_virt_timer.deactivate_timer(BX_PIT_THIS s.timer_handle[0]); BX_DEBUG(("deactivated timer")); if(BX_PIT_THIS s.timer.get_next_event_time()) { bx_virt_timer.activate_timer(BX_PIT_THIS s.timer_handle[0], (Bit32u)BX_MAX(1,TICKS_TO_USEC(BX_PIT_THIS s.timer.get_next_event_time())), 0); BX_DEBUG(("activated timer")); } BX_PIT_THIS s.last_next_event_time = BX_PIT_THIS s.timer.get_next_event_time(); } BX_DEBUG(("s.last_usec="FMT_LL"d", BX_PIT_THIS s.last_usec)); BX_DEBUG(("s.timer_id=%d", BX_PIT_THIS s.timer_handle[0])); BX_DEBUG(("s.timer.get_next_event_time=%x", BX_PIT_THIS s.timer.get_next_event_time())); BX_DEBUG(("s.last_next_event_time=%d", BX_PIT_THIS s.last_next_event_time)); }
ulong get_timer(ulong base) { ulong now = get_timer_masked(); if (now >= base) return now - base; else return TICKS_TO_USEC(0xFFFFFFFFUL) - (base - now) ; }
//Called when next_event_time changes. void bx_virt_timer_c::next_event_time_update(void) { virtual_next_event_time = timers_next_event_time + current_timers_time - current_virtual_time; if (init_done) { bx_pc_system.deactivate_timer(system_timer_id); BX_ASSERT(virtual_next_event_time); bx_pc_system.activate_timer(system_timer_id, (Bit32u)BX_MIN(0x7FFFFFFF,BX_MAX(1,TICKS_TO_USEC(virtual_next_event_time))), 0); } }
void bx_pit_c::init(void) { DEV_register_irq(0, "8254 PIT"); DEV_register_ioread_handler(this, read_handler, 0x0040, "8254 PIT", 1); DEV_register_ioread_handler(this, read_handler, 0x0041, "8254 PIT", 1); DEV_register_ioread_handler(this, read_handler, 0x0042, "8254 PIT", 1); DEV_register_ioread_handler(this, read_handler, 0x0043, "8254 PIT", 1); DEV_register_ioread_handler(this, read_handler, 0x0061, "8254 PIT", 1); DEV_register_iowrite_handler(this, write_handler, 0x0040, "8254 PIT", 1); DEV_register_iowrite_handler(this, write_handler, 0x0041, "8254 PIT", 1); DEV_register_iowrite_handler(this, write_handler, 0x0042, "8254 PIT", 1); DEV_register_iowrite_handler(this, write_handler, 0x0043, "8254 PIT", 1); DEV_register_iowrite_handler(this, write_handler, 0x0061, "8254 PIT", 1); BX_DEBUG(("starting init")); BX_PIT_THIS s.speaker_data_on = 0; BX_PIT_THIS s.refresh_clock_div2 = 0; BX_PIT_THIS s.timer.init(); BX_PIT_THIS s.timer.set_OUT_handler(0, irq_handler); Bit64u my_time_usec = bx_virt_timer.time_usec(); if (BX_PIT_THIS s.timer_handle[0] == BX_NULL_TIMER_HANDLE) { BX_PIT_THIS s.timer_handle[0] = bx_virt_timer.register_timer(this, timer_handler, (unsigned) 100 , 1, 1, "pit_wrap"); } BX_DEBUG(("RESETting timer.")); bx_virt_timer.deactivate_timer(BX_PIT_THIS s.timer_handle[0]); BX_DEBUG(("deactivated timer.")); if (BX_PIT_THIS s.timer.get_next_event_time()) { bx_virt_timer.activate_timer(BX_PIT_THIS s.timer_handle[0], (Bit32u)BX_MAX(1,TICKS_TO_USEC(BX_PIT_THIS s.timer.get_next_event_time())), 0); BX_DEBUG(("activated timer.")); } BX_PIT_THIS s.last_next_event_time = BX_PIT_THIS s.timer.get_next_event_time(); BX_PIT_THIS s.last_usec = my_time_usec; BX_PIT_THIS s.total_ticks = 0; BX_PIT_THIS s.total_usec = 0; BX_DEBUG(("finished init")); BX_DEBUG(("s.last_usec="FMT_LL"d",BX_PIT_THIS s.last_usec)); BX_DEBUG(("s.timer_id=%d",BX_PIT_THIS s.timer_handle[0])); BX_DEBUG(("s.timer.get_next_event_time=%d", BX_PIT_THIS s.timer.get_next_event_time())); BX_DEBUG(("s.last_next_event_time=%d", BX_PIT_THIS s.last_next_event_time)); }
void bx_virt_timer_c::timer_handler(void) { if(!virtual_timers_realtime) { Bit64u temp_final_time = bx_pc_system.time_usec(); temp_final_time -= current_virtual_time; while (temp_final_time) { if((temp_final_time)>(virtual_next_event_time)) { temp_final_time -= virtual_next_event_time; advance_virtual_time(virtual_next_event_time); } else { advance_virtual_time(temp_final_time); temp_final_time -= temp_final_time; } } bx_pc_system.activate_timer(system_timer_id, (Bit32u)BX_MIN(0x7FFFFFFF,(virtual_next_event_time>2)?(virtual_next_event_time-2):1), 0); return; } Bit64u usec_delta = bx_pc_system.time_usec()-last_usec; if (usec_delta) { #if BX_HAVE_REALTIME_USEC Bit64u ticks_delta = 0; Bit64u real_time_delta = GET_VIRT_REALTIME64_USEC() - last_real_time - real_time_delay; Bit64u real_time_total = real_time_delta + total_real_usec; Bit64u system_time_delta = (Bit64u)usec_delta + (Bit64u)stored_delta; if(real_time_delta) { last_realtime_delta = real_time_delta; last_realtime_ticks = total_ticks; } ticks_per_second = USEC_PER_SECOND; //Start out with the number of ticks we would like // to have to line up with real time. ticks_delta = real_time_total - total_ticks; if(real_time_total < total_ticks) { //This slows us down if we're already ahead. // probably only an issue on startup, but it solves some problems. ticks_delta = 0; } if(ticks_delta + total_ticks - last_realtime_ticks > (F2I(MAX_MULT * I2F(last_realtime_delta)))) { //This keeps us from going too fast in relation to real time. #if 0 ticks_delta = (F2I(MAX_MULT * I2F(last_realtime_delta))) + last_realtime_ticks - total_ticks; #endif ticks_per_second = F2I(MAX_MULT * I2F(USEC_PER_SECOND)); } if(ticks_delta > system_time_delta * USEC_PER_SECOND / MIN_USEC_PER_SECOND) { //This keeps us from having too few instructions between ticks. ticks_delta = system_time_delta * USEC_PER_SECOND / MIN_USEC_PER_SECOND; } if(ticks_delta > virtual_next_event_time) { //This keeps us from missing ticks. ticks_delta = virtual_next_event_time; } if(ticks_delta) { # if DEBUG_REALTIME_WITH_PRINTF //Every second print some info. if(((last_real_time + real_time_delta) / USEC_PER_SECOND) > (last_real_time / USEC_PER_SECOND)) { Bit64u temp1, temp2, temp3, temp4; temp1 = (Bit64u) total_real_usec; temp2 = (total_real_usec); temp3 = (Bit64u)total_ticks; temp4 = (Bit64u)((total_real_usec) - total_ticks); printf("useconds: " FMT_LL "u, ", temp1); printf("expect ticks: " FMT_LL "u, ", temp2); printf("ticks: " FMT_LL "u, ", temp3); printf("diff: "FMT_LL "u\n", temp4); } # endif last_real_time += real_time_delta; total_real_usec += real_time_delta; last_system_usec += system_time_delta; stored_delta = 0; total_ticks += ticks_delta; } else { stored_delta = system_time_delta; } Bit64u a = usec_per_second, b; if(real_time_delta) { //FIXME Bit64u em_realtime_delta = last_system_usec + stored_delta - em_last_realtime; b=((Bit64u)USEC_PER_SECOND * em_realtime_delta / real_time_delta); em_last_realtime = last_system_usec + stored_delta; } else { b=a; } usec_per_second = ALPHA_LOWER(a,b); #else BX_ASSERT(0); #endif #if BX_HAVE_REALTIME_USEC advance_virtual_time(ticks_delta); #endif } last_usec=last_usec + usec_delta; bx_pc_system.deactivate_timer(system_timer_id); BX_ASSERT(virtual_next_event_time); bx_pc_system.activate_timer(system_timer_id, (Bit32u)BX_MIN(0x7FFFFFFF,BX_MAX(1,TICKS_TO_USEC(virtual_next_event_time))), 0); }
ulong get_timer_masked(void) { return TICKS_TO_USEC(get_timer_raw()); }
void bx_pit_c::write(Bit32u address, Bit32u dvalue, unsigned io_len) { #else UNUSED(this_ptr); #endif // !BX_USE_PIT_SMF Bit8u value; Bit64u my_time_usec = bx_virt_timer.time_usec(); Bit64u time_passed = my_time_usec-BX_PIT_THIS s.last_usec; Bit32u time_passed32 = (Bit32u)time_passed; if(time_passed32) { periodic(time_passed32); } BX_PIT_THIS s.last_usec = BX_PIT_THIS s.last_usec + time_passed; value = (Bit8u) dvalue; BX_DEBUG(("write to port 0x%04x, value = 0x%02x", address, value)); switch (address) { case 0x40: /* timer 0: write count register */ BX_PIT_THIS s.timer.write(0, value); break; case 0x41: /* timer 1: write count register */ BX_PIT_THIS s.timer.write(1, value); break; case 0x42: /* timer 2: write count register */ BX_PIT_THIS s.timer.write(2, value); break; case 0x43: /* timer 0-2 mode control */ BX_PIT_THIS s.timer.write(3, value); break; case 0x61: BX_PIT_THIS s.speaker_data_on = (value >> 1) & 0x01; if (BX_PIT_THIS s.speaker_data_on) { DEV_speaker_beep_on((float)(1193180.0 / BX_PIT_THIS get_timer(2))); } else { DEV_speaker_beep_off(); } /* ??? only on AT+ */ BX_PIT_THIS s.timer.set_GATE(2, value & 0x01); break; default: BX_PANIC(("unsupported io write to port 0x%04x = 0x%02x", address, value)); } if (time_passed || (BX_PIT_THIS s.last_next_event_time != BX_PIT_THIS s.timer.get_next_event_time())) { BX_DEBUG(("RESETting timer")); bx_virt_timer.deactivate_timer(BX_PIT_THIS s.timer_handle[0]); BX_DEBUG(("deactivated timer")); if(BX_PIT_THIS s.timer.get_next_event_time()) { bx_virt_timer.activate_timer(BX_PIT_THIS s.timer_handle[0], (Bit32u)BX_MAX(1,TICKS_TO_USEC(BX_PIT_THIS s.timer.get_next_event_time())), 0); BX_DEBUG(("activated timer")); } BX_PIT_THIS s.last_next_event_time = BX_PIT_THIS s.timer.get_next_event_time(); } BX_DEBUG(("s.last_usec="FMT_LL"d", BX_PIT_THIS s.last_usec)); BX_DEBUG(("s.timer_id=%d", BX_PIT_THIS s.timer_handle[0])); BX_DEBUG(("s.timer.get_next_event_time=%x", BX_PIT_THIS s.timer.get_next_event_time())); BX_DEBUG(("s.last_next_event_time=%d", BX_PIT_THIS s.last_next_event_time)); }