void emu_run() { void *timer = sys_timer(); int delay; vid_begin(); lcd_begin(); for (;;) { cpu_emulate(2280); while (R_LY > 0 && R_LY < 144) emu_step(); vid_end(); rtc_tick(); sound_mix(); if (!pcm_submit()) { delay = framelen - sys_elapsed(timer); sys_sleep(delay); sys_elapsed(timer); } doevents(); vid_begin(); if (framecount) { if (!--framecount) die("finished\n"); } if (!(R_LCDC & 0x80)) cpu_emulate(32832); while (R_LY > 0) /* wait for next frame */ emu_step(); } }
/* Time intervals throughout the code, unless otherwise noted, are specified in double-speed machine cycles (2MHz), each unit roughly corresponds to 0.477us. For CPU each cycle takes 2dsc (0.954us) in single-speed mode and 1dsc (0.477us) in double speed mode. Although hardware gbc LCDC would operate at completely different and fixed frequency, for emulation purposes timings for it are also specified in double-speed cycles. line = 228 dsc (109us) frame (154 lines) = 35112 dsc (16.7ms) of which visible lines x144 = 32832 dsc (15.66ms) vblank lines x10 = 2280 dsc (1.08ms) */ void emu_run() { void *timer = sys_timer(); int delay; vid_begin(); lcd_begin(); for (;;) { /* FRAME BEGIN */ /* FIXME: djudging by the time specified this was intended to emulate through vblank phase which is handled at the end of the loop. */ cpu_emulate(2280); /* FIXME: R_LY >= 0; comparsion to zero can also be removed altogether, R_LY is always 0 at this point */ while (R_LY > 0 && R_LY < 144) { /* Step through visible line scanning phase */ emu_step(); } /* VBLANK BEGIN */ vid_end(); rtc_tick(); sound_mix(); /* pcm_submit() introduces delay, if it fails we use sys_sleep() instead */ if (!pcm_submit()) { delay = framelen - sys_elapsed(timer); sys_sleep(delay); sys_elapsed(timer); } doevents(); vid_begin(); if (framecount) { if (!--framecount) die("finished\n"); } if (!(R_LCDC & 0x80)) { /* LCDC operation stopped */ /* FIXME: djudging by the time specified, this is intended to emulate through visible line scanning phase, even though we are already at vblank here */ cpu_emulate(32832); } while (R_LY > 0) { /* Step through vblank phase */ emu_step(); } /* VBLANK END */ /* FRAME END */ } }
int regulate(unsigned long _interval) { unsigned long now=timeGetTime(); if(now>regulate_timestamp){ if(now-regulate_timestamp<_interval){ _interval-=(now-regulate_timestamp); }else{ _interval=0; } }else{ _interval=_interval; } unsigned long nexttime=now+_interval; do{ if(doevents()!=0)return -1; }while(timeGetTime()<nexttime); regulate_timestamp=timeGetTime(); return 0; }
int main(void) { __Set(BEEP_VOLUME, 0); // USART1 8N1 115200bps debug port RCC->APB2ENR |= RCC_APB2ENR_USART1EN; USART1->BRR = 72000000 / 115200; USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; gpio_usart1_tx_mode(GPIO_AFOUT_10); gpio_usart1_rx_mode(GPIO_HIGHZ_INPUT); printf("\nBoot!\n"); // Reduce the wait states of the FPGA & LCD interface // It works for me, hopefully it works for you too :) FSMC_BTR1 = 0x10100110; FSMC_BTR2 = 0x10100110; __Set(ADC_CTRL, EN); __Set(ADC_MODE, SEPARATE); alterbios_init(); int status = alterbios_check(); if (status < 0) { char buf[100]; snprintf(buf, sizeof(buf), "AlterBIOS not found or too old: %d\n" "Please install it from https://github.com/PetteriAimonen/AlterBIOS", status); while (1) show_msgbox("AlterBIOS is required", buf); } get_keys(ALL_KEYS); // Clear key buffer while (true) { select_file(amx_filename); get_keys(ANY_KEY); __Clear_Screen(0); char error[50] = {0}; int status = loadprogram(amx_filename, error, sizeof(error)); if (status != 0) { char buffer[200]; snprintf(buffer, sizeof(buffer), "Loading of program %s failed:\n\n" "Error %d: %s\n\n" "%s\n", amx_filename, status, my_aux_StrError(status), error); printf(buffer); printf(amx_filename); show_msgbox("Program load failed", buffer); } else { int idle_func = -1; if (amx_FindPublic(&amx, "@idle", &idle_func) != 0) idle_func = -1; cell ret; status = amx_Exec(&amx, &ret, AMX_EXEC_MAIN); while (status == AMX_ERR_SLEEP) { AMX nested_amx = amx; uint32_t end = get_time() + amx.pri; do { status = doevents(&nested_amx); } while (get_time() < end && status == 0); if (status == 0) status = amx_Exec(&amx, &ret, AMX_EXEC_CONT); else amx = nested_amx; // Report errors properly } if (status == 0 && idle_func != -1) { // Main() exited, keep running idle function. do { status = doevents(&amx); if (status == 0) status = amx_Exec(&amx, &ret, idle_func); } while (status == 0 && ret != 0); } amxcleanup_wavein(&amx); amxcleanup_file(&amx); if (status == AMX_ERR_EXIT && ret == 0) status = 0; // Ignore exit(0), but inform about e.g. exit(1) if (status != 0) { show_pawn_traceback(amx_filename, &amx, status); } else { draw_menubar("Close", "", "", ""); while (!get_keys(BUTTON1)); } } } return 0; }