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 */ } }
void lcdc_change(byte b) { byte old = R_LCDC; R_LCDC = b; if ((R_LCDC ^ old) & 0x80) /* lcd on/off change */ { R_LY = 0; stat_change(2); C = 40; lcd_begin(); } }
void lcdc_change(byte b) { byte old = R_LCDC; R_LCDC = b; if ((R_LCDC ^ old) & 0x80) /* lcd on/off change */ { /* FIXME; LCDC startup approach has changed; leave lcd_begin() out, set state to zero, set C to zero, call lcdc_change() once, it will do what is necessary */ R_LY = 0; stat_change(2); C = 40; lcd_begin(); } }
void emu_init(int game_id) { vid_init(); pcm_init(); vid_preinit(); // load ROM & load palette bitbox_rom_load(game_id); emu_reset(); vid_begin(); lcd_begin(); emu_started = 1; // at the end , start line blitting }
/* lcdc_trans() Main LCDC emulation routine */ void lcdc_trans() { if (R_LCDC & 0x80) { /* LCDC operation enabled */ while (C <= 0) { /* Update current state */ switch ((byte)(R_STAT & 3)) { case 0: /* after hblank */ /* FIXME: first line of first frame will be skipped each time LCDC is started */ if (++R_LY <= 143) { stat_change(2); /* -> search */ } else { stat_change(1); /* -> vblank */ /* See "NOTE A" above */ /*if (cpu.halt) { hw_interrupt(IF_VBLANK, IF_VBLANK); C += 228; } else { C += 10; continue; }*/ break; } break; case 2: /* after search */ stat_change(3); /* -> transfer */ break; case 3: /* after transfer */ stat_change(0); /* -> hblank */ break; case 1: /* after (in) vblank */ if (R_LY == 0) { stat_change(2); /* -> search */ } break; } /* Handle current state */ switch ((byte)(R_STAT & 3)) { case 2: /* search */ if (R_LY == 0) { lcd_begin(); } C += 40; break; case 3: /* transfer */ lcd_refreshline(); C += 86; break; case 0: /* hblank */ if (hw.hdma & 0x80) { hw_hdma(); } C += 102; break; case 1: /* vblank */ if (!(hw.ilines & IF_VBLANK)) { C += 228; /*C += 218; See "NOTE A" above */ hw_interrupt(IF_VBLANK, IF_VBLANK); } else { R_LY++; if (R_LY < 153) { C += 228; } else if (R_LY == 153) { /* Handling special case on the last line part 1; see docs/HACKING */ C += 28; } else { /* Handling special case on the last line part 2; see docs/HACKING */ R_LY = 0; C += 200; } stat_trigger(); } break; } /* switch(state) */ } /* while (C <= 0) */ } /* if (R_LCDC & 0x80) */ else { /* LCDC operation disabled (short route) */ if (C <= 0) /* Original code does in fact return after each pass, there is no loop here */ { switch ((byte)(R_STAT & 3)) { case 2: /* after search */ stat_change(3); C += 86; break; case 3: /* after transfer */ stat_change(0); C += 102; break; case 0: /* after hblank */ stat_change(2); R_LY++; C += 40; break; case 1: /* after (in) vblank */ stat_change(2); C += 40; break; } } } }
void emu_run() { int delta; // too much #ifdef MEASUREMENT int cur_frame=0; //mitzahlen int time_hs; void *timer; #endif delta = 0; lcd_begin(); //cop_begin(); while(emu_running) { #ifdef MEASUREMENT if(cur_frame==MESS_START) { cop_end(); err_msg("Measuring", 100); err_msg("Measuring.", 100); err_msg("Measuring..", 100); err_msg("Measuring...", 100); cop_begin(); timer = sys_timer(); } if(cur_frame==MESS_END) { time_hs = sys_elapsed(timer)/10000; emu_running = 0; } cur_frame++; #endif #ifdef USE_DEBUG if(delta >= 2280) printf("too much %6d\n", delta); else if(delta < 0) printf("delta is negative"); #endif delta = -cpu_emulate(2280 - delta); while (R_LY > 0 && R_LY < 144) { if(cpu.lcdc > delta){ delta = -cpu_emulate(cpu.lcdc-delta); } else{ delta -= cpu.lcdc; } } rtc_tick(); sound_mix(); pcm_submit(); kb_poll(); if (!(R_LCDC & 0x80)) delta = -cpu_emulate(32832 - delta); // wait for next frame while (R_LY > 0) { if(cpu.lcdc > delta){ delta = -cpu_emulate(cpu.lcdc-delta); } else{ delta -= cpu.lcdc; } } /*cpu_emulate(2280-delta); while (R_LY > 0 && R_LY < 144) delta = -cpu_emulate(cpu.lcdc); rtc_tick(); sound_mix(); pcm_submit(); kb_poll(); if (!(R_LCDC & 0x80)) delta = -cpu_emulate(32832); // wait for next frame while (R_LY > 0) delta = -cpu_emulate(cpu.lcdc);*/ } #ifdef MEASUREMENT cop_end(); err_msg("%d hs", 3000, time_hs); enter_menu(); #endif }
void lcd_setup() { lcd_begin(LCD_I2C_ADDR, MAX_LCD_LINE_LEN, LCD_NUM_LINES, LCD_5x8DOTS); lcd_backlight(); // can't define this as the zeroth character as zero is null in sprintf! :) lcd_createChar(1, backslashChar); }
void lcdc_trans() { if (!(R_LCDC & 0x80)) { while (C <= 0) { switch ((byte)(R_STAT & 3)) { case 0: case 1: stat_change(2); C += 40; break; case 2: stat_change(3); C += 86; break; case 3: stat_change(0); if (hw.hdma & 0x80) hw_hdma(); else C += 102; break; } return; } } while (C <= 0) { switch ((byte)(R_STAT & 3)) { case 1: if (!(hw.ilines & IF_VBLANK)) { C += 218; hw_interrupt(IF_VBLANK, IF_VBLANK); break; } if (R_LY == 0) { lcd_begin(); stat_change(2); C += 40; break; } else if (R_LY < 152) C += 228; else if (R_LY == 152) C += 28; else { R_LY = -1; C += 200; } R_LY++; stat_trigger(); break; case 2: lcd_refreshline(); stat_change(3); C += 86; break; case 3: stat_change(0); if (hw.hdma & 0x80) hw_hdma(); /* FIXME -- how much of the hblank does hdma use?? */ /* else */ C += 102; break; case 0: if (++R_LY >= 144) { if (cpu.halt) { hw_interrupt(IF_VBLANK, IF_VBLANK); C += 228; } else C += 10; stat_change(1); break; } stat_change(2); C += 40; break; } } }