void TIMER_Write(const v810_timestamp_t ×tamp, uint32 A, uint8 V) { if(A & 0x3) { puts("HWCtrl Bogus Write?"); return; } TIMER_Update(timestamp); //if((A & 0xFF) <= 0x1C) //printf("Write: %d, %08x %02x\n", timestamp, A, V); switch(A & 0xFF) { case 0x18: TimerReloadValue &= 0xFF00; TimerReloadValue |= V; ReloadPending = true; break; case 0x1C: TimerReloadValue &= 0x00FF; TimerReloadValue |= V << 8; ReloadPending = true; break; case 0x20: if(V & TC_ZSTATCLR) { if((TimerControl & TC_TENABLE) && TimerCounter == 0) { //puts("Faulty Z-Stat-Clr"); } else { TimerStatus = false; } TimerStatusShadow = false; } if((V & TC_TENABLE) && !(TimerControl & TC_TENABLE)) { //TimerCounter = TimerReloadValue; TimerDivider = (V & TC_TCLKSEL) ? 500 : 2000; } TimerControl = V & (0x10 | 0x08 | 0x01); if(!(TimerControl & TC_TIMZINT)) TimerStatus = TimerStatusShadow = false; VBIRQ_Assert(VBIRQ_SOURCE_TIMER, TimerStatusShadow && (TimerControl & TC_TIMZINT)); if(TimerControl & TC_TENABLE) VB_SetEvent(VB_EVENT_TIMER, timestamp + TimerDivider); break; } }
static void ForceEventUpdates(const pscpu_timestamp_t timestamp) { PSX_SetEventNT(PSX_EVENT_GPU, GPU->Update(timestamp)); PSX_SetEventNT(PSX_EVENT_CDC, CDC->Update(timestamp)); PSX_SetEventNT(PSX_EVENT_TIMER, TIMER_Update(timestamp)); PSX_SetEventNT(PSX_EVENT_DMA, DMA_Update(timestamp)); PSX_SetEventNT(PSX_EVENT_FIO, FIO->Update(timestamp)); CPU->SetEventNT(events[PSX_EVENT__SYNFIRST].next->event_time); }
void EventLoop() { CLOCK_ResetWatchdog(); unsigned int time; #ifdef HEAP_DEBUG static int heap = 0; int h = _sbrk_r(NULL, 0); if(h > heap) { printf("heap: %x\n", h); heap = h; } #endif #ifdef TIMING_DEBUG debug_timing(0, 0); #endif priority_ready &= ~(1 << MEDIUM_PRIORITY); if(PWR_CheckPowerSwitch()) { if(! (BATTERY_Check() & BATTERY_CRITICAL)) { CONFIG_SaveModelIfNeeded(); CONFIG_SaveTxIfNeeded(); } if(Transmitter.music_shutdown) { MUSIC_Play(MUSIC_SHUTDOWN); // We wait ~1sec for shutdown music finished time = CLOCK_getms()+700; while(CLOCK_getms()<time); } PWR_Shutdown(); } BUTTON_Handler(); TOUCH_Handler(); if (priority_ready & (1 << LOW_PRIORITY)) { priority_ready &= ~(1 << LOW_PRIORITY); PAGE_Event(); PROTOCOL_CheckDialogs(); TIMER_Update(); TELEMETRY_Alarm(); BATTERY_Check(); AUTODIMMER_Update(); #if DATALOG_ENABLED DATALOG_Update(); #endif GUI_RefreshScreen(); } #ifdef TIMING_DEBUG debug_timing(0, 1); #endif }
uint8 TIMER_Read(const v810_timestamp_t ×tamp, uint32 A) { uint8 ret = 0; //if(A <= 0x1C) //printf("Read: %d, %08x\n", timestamp, A); TIMER_Update(timestamp); switch(A & 0xFF) { case 0x18: ret = TimerCounter; break; case 0x1C: ret = TimerCounter >> 8; break; case 0x20: ret = TimerControl | (0xE0 | TC_ZSTATCLR) | (TimerStatus ? TC_ZSTAT : 0); break; } return(ret); }
bool MDFN_FASTCALL PSX_EventHandler(const pscpu_timestamp_t timestamp) { event_list_entry *e = events[PSX_EVENT__SYNFIRST].next; #ifdef PSX_EVENT_SYSTEM_CHECKS pscpu_timestamp_t prev_event_time = 0; #endif #if 0 { printf("EventHandler - timestamp=%8d\n", timestamp); event_list_entry *moo = &events[PSX_EVENT__SYNFIRST]; while(moo) { printf("%u: %8d\n", moo->which, moo->event_time); moo = moo->next; } } #endif #ifdef PSX_EVENT_SYSTEM_CHECKS assert(Running == 0 || timestamp >= e->event_time); // If Running == 0, our EventHandler #endif while(timestamp >= e->event_time) // If Running = 0, PSX_EventHandler() may be called even if there isn't an event per-se, so while() instead of do { ... } while { event_list_entry *prev = e->prev; pscpu_timestamp_t nt; #ifdef PSX_EVENT_SYSTEM_CHECKS // Sanity test to make sure events are being evaluated in temporal order. if(e->event_time < prev_event_time) abort(); prev_event_time = e->event_time; #endif //printf("Event: %u %8d\n", e->which, e->event_time); #ifdef PSX_EVENT_SYSTEM_CHECKS if((timestamp - e->event_time) > 50) printf("Late: %u %d --- %8d\n", e->which, timestamp - e->event_time, timestamp); #endif switch(e->which) { default: abort(); case PSX_EVENT_GPU: nt = GPU->Update(e->event_time); break; case PSX_EVENT_CDC: nt = CDC->Update(e->event_time); break; case PSX_EVENT_TIMER: nt = TIMER_Update(e->event_time); break; case PSX_EVENT_DMA: nt = DMA_Update(e->event_time); break; case PSX_EVENT_FIO: nt = FIO->Update(e->event_time); break; } #ifdef PSX_EVENT_SYSTEM_CHECKS assert(nt > e->event_time); #endif PSX_SetEventNT(e->which, nt); // Order of events can change due to calling PSX_SetEventNT(), this prev business ensures we don't miss an event due to reordering. e = prev->next; } #ifdef PSX_EVENT_SYSTEM_CHECKS for(int i = PSX_EVENT__SYNFIRST + 1; i < PSX_EVENT__SYNLAST; i++) { if(timestamp >= events[i].event_time) { printf("BUG: %u\n", i); event_list_entry *moo = &events[PSX_EVENT__SYNFIRST]; while(moo) { printf("%u: %8d\n", moo->which, moo->event_time); moo = moo->next; } abort(); } } #endif //#ifdef PSX_EVENT_SYSTEM_CHECKS // abort(); //#endif return(Running); }
void EventLoop() { CLOCK_ResetWatchdog(); #ifdef HEAP_DEBUG static int heap = 0; int h = _sbrk_r(NULL, 0); if(h > heap) { printf("heap: %x\n", h); heap = h; } #endif #ifdef TIMING_DEBUG debug_timing(0, 0); #endif priority_ready &= ~(1 << MEDIUM_PRIORITY); #if !HAS_HARD_POWER_OFF if(PWR_CheckPowerSwitch()) { if(! (BATTERY_Check() & BATTERY_CRITICAL)) { PAGE_Test(); CONFIG_SaveModelIfNeeded(); CONFIG_SaveTxIfNeeded(); } if(Transmitter.music_shutdown) { #if HAS_EXTENDED_AUDIO if(AUDIO_VoiceAvailable()) { MUSIC_Play(MUSIC_SHUTDOWN); while (CLOCK_getms() < audio_queue_time) { // Wait for voice to finished CLOCK_ResetWatchdog(); } } else { #else { // We wait ~1sec for shutdown buzzer music finished unsigned int time; MUSIC_Play(MUSIC_SHUTDOWN); time = CLOCK_getms()+700; while (CLOCK_getms() < time) { CLOCK_ResetWatchdog(); } #endif } } PWR_Shutdown(); } #endif BUTTON_Handler(); TOUCH_Handler(); INPUT_CheckChanges(); if (priority_ready & (1 << LOW_PRIORITY)) { priority_ready &= ~(1 << LOW_PRIORITY); PAGE_Event(); PROTOCOL_CheckDialogs(); TIMER_Update(); TELEMETRY_Alarm(); BATTERY_Check(); AUTODIMMER_Update(); #if HAS_DATALOG DATALOG_Update(); #endif #if HAS_VIDEO VIDEO_Update(); #endif #if HAS_EXTENDED_AUDIO AUDIO_CheckQueue(); #endif GUI_RefreshScreen(); #if HAS_HARD_POWER_OFF if (PAGE_ModelDoneEditing()) CONFIG_SaveModelIfNeeded(); CONFIG_SaveTxIfNeeded(); #endif } #ifdef TIMING_DEBUG debug_timing(0, 1); #endif } void TOUCH_Handler() { if(! HAS_TOUCH) return; u32 pen_down=0; static u32 pen_down_last=0; static u32 pen_down_long_at=0; struct touch t; if(SPITouch_IRQ()) { pen_down=1; t=SPITouch_GetCoords(); if (! pen_down_last) pen_down_long_at=CLOCK_getms()+500; } else { pen_down=0; } if(pen_down && (!pen_down_last)) { AUTODIMMER_Check(); GUI_CheckTouch(&t, 0); } if(!pen_down && pen_down_last) { GUI_TouchRelease(); } if(pen_down && pen_down_last) { if(CLOCK_getms()>pen_down_long_at) { GUI_CheckTouch(&t, 1); pen_down_long_at += 100; } } pen_down_last=pen_down; } #if HAS_VIDEO void VIDEO_Update() { static u8 video_enable = 0; static u32 check_standard_ms = 0; // Check if Video is turn on int enabled = MIXER_SourceAsBoolean(Model.videosrc); if (enabled != video_enable) { VIDEO_Enable(enabled); video_enable = enabled; if (enabled) { VIDEO_SetChannel(Model.videoch); VIDEO_Contrast(Model.video_contrast); VIDEO_Brightness(Model.video_brightness); check_standard_ms = CLOCK_getms() + 3000; } else check_standard_ms = 0; } if(video_enable && check_standard_ms > 0 && check_standard_ms < CLOCK_getms()) { u8 video_standard_current = VIDEO_GetStandard(); if((video_standard_current > 0) && (video_standard_current < 8)) { VIDEO_SetStandard(video_standard_current); check_standard_ms = 0; } else { check_standard_ms = CLOCK_getms() + 3000; } } if(video_enable) AUTODIMMER_Check(); } #endif //HAS_VIDEO #ifdef TIMING_DEBUG void debug_timing(u32 type, int startend) { static u32 last_time[2][100]; static u32 loop_time[4][101]; static u32 loop_pos[4] = {-1, -1, -1, -1}; static u32 max_last[2]; static u32 max_loop[4]; static int save_priority; if (type == 0) { if (! startend) save_priority = priority_ready; if (save_priority & (1 << MEDIUM_PRIORITY)) debug_timing(2, startend); if (save_priority & (1 << LOW_PRIORITY)) debug_timing(1, startend); return; } type--; if (! startend) { u32 t = CLOCK_getms(); loop_pos[type] = (loop_pos[type] + 1) % 100; if (type < 2) { last_time[type][loop_pos[type]] = t; if (t - last_time[type][(loop_pos[type] + 99) % 100] > max_last[type]) max_last[type] = t - last_time[type][(loop_pos[type] + 99) % 100]; } loop_time[type][100] = t; } else { loop_time[type][loop_pos[type]] = CLOCK_getms() - loop_time[type][100]; if (loop_time[type][loop_pos[type]] > max_loop[type]) max_loop[type] = loop_time[type][loop_pos[type]]; if (type == 0 && loop_pos[0] == 99) { unsigned avg_loop[4] = {0, 0, 0, 0}; unsigned avg_last[2] = {0, 0}; for(int i = 0; i < 99; i++) { for(int t = 0; t < 2; t++) { u32 delay = last_time[t][(i + loop_pos[t] + 2) % 100] - last_time[t][(i + loop_pos[t] + 1) % 100]; avg_last[t] += delay; } for(int t = 0; t < 4; t++) avg_loop[t] += loop_time[t][i]; } for(int t = 0; t < 4; t++) avg_loop[t] /= 99; avg_last[0] /= 99; avg_last[1] /= 99; printf("Avg: radio: %d mix: %d med: %d/%d low: %d/%d\n", avg_loop[3], avg_loop[2], avg_loop[1], avg_last[1], avg_loop[0], avg_last[0]); printf("Max: radio: %d mix: %d med: %d/%d low: %d/%d\n", max_loop[3], max_loop[2], max_loop[1], max_last[1], max_loop[0], max_last[0]); memset(max_loop, 0, sizeof(max_loop)); max_last[0] = 0; max_last[1] = 0; } } } #endif void debug_switches() { s32 data[INP_LAST]; for(int i = INP_HAS_CALIBRATION+1; i < INP_LAST; i++) { data[i] = CHAN_ReadRawInput(i); } while(1) { u32 changed = 0; for(int i = INP_HAS_CALIBRATION+1; i < INP_LAST; i++) { s32 val = CHAN_ReadRawInput(i); if (val != data[i]) { printf("%s=%d ", INPUT_SourceName(tempstring, i), val); data[i] = val; changed = 1; } } if (changed) { printf("\n"); } if(PWR_CheckPowerSwitch()) PWR_Shutdown(); } }