X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=gp2x%2Femu.c;h=eca0dc4d99247b6c437ce35c25de687fc41368aa;hb=576fc637929cdfc92884e2e92c6c22e002cfb000;hp=a98a5be86576f11430b005b2eae376bb5d291698;hpb=2fb6c387829e4a8cabb7f45490a8aa792d068ee0;p=libpicofe.git diff --git a/gp2x/emu.c b/gp2x/emu.c index a98a5be..eca0dc4 100644 --- a/gp2x/emu.c +++ b/gp2x/emu.c @@ -1,4 +1,4 @@ -// (c) Copyright 2006 notaz, All rights reserved. +// (c) Copyright 2006-2007 notaz, All rights reserved. // Free for non-commercial use. // For commercial use, separate licencing terms must be obtained. @@ -54,29 +54,16 @@ extern int crashed_940; static short sndBuffer[2*44100/50]; static char noticeMsg[64]; // notice msg to draw static struct timeval noticeMsgTime = { 0, 0 }; // when started showing -static int reset_timing, osd_fps_x; +static int osd_fps_x; static int combo_keys = 0, combo_acts = 0; // keys and actions which need button combos static int gp2x_old_gamma = 100; static unsigned char *movie_data = NULL; static int movie_size = 0; unsigned char *framebuff = 0; // temporary buffer for alt renderer int state_slot = 0; +int reset_timing = 0; -/* -// tmp -static FILE *logf = NULL; -void pprintf(char *texto, ...) -{ - va_list args; - - va_start(args,texto); - vfprintf(logf,texto,args); - va_end(args); - fflush(logf); - sync(); -} -*/ // utilities static void strlwr(char* string) { @@ -169,7 +156,7 @@ int find_bios(int region, char **bios_file) /* checks if romFileName points to valid MegaCD image * if so, checks for suitable BIOS */ -static int cd_check(char **bios_file) +int emu_cd_check(char **bios_file) { unsigned char buf[32]; pm_file *cd_f; @@ -190,7 +177,7 @@ static int cd_check(char **bios_file) return 0; } - /* it seems we have a CD image here. Try to detect region and load a suitable BIOS now.. */ + /* it seems we have a CD image here. Try to detect region now.. */ pm_seek(cd_f, (type == 1) ? 0x100+0x10B : 0x110+0x10B, SEEK_SET); pm_read(buf, 1, cd_f); pm_close(cd_f); @@ -206,7 +193,9 @@ static int cd_check(char **bios_file) printf("overrided region to %s\n", region != 4 ? (region == 8 ? "EU" : "JAP") : "USA"); } - if(find_bios(region, bios_file)) + if (bios_file == NULL) return type; + + if (find_bios(region, bios_file)) return type; // CD and BIOS detected return -1; // CD detected but load failed @@ -283,8 +272,11 @@ int emu_ReloadRom(void) get_ext(romFileName, ext); } + if ((PicoMCD & 1) && Pico_mcd != NULL) + Stop_CD(); + // check for MegaCD image - cd_state = cd_check(&used_rom_name); + cd_state = emu_cd_check(&used_rom_name); if (cd_state > 0) { PicoMCD |= 1; get_ext(used_rom_name, ext); @@ -318,7 +310,7 @@ int emu_ReloadRom(void) // detect wrong files (Pico crashes on very small files), also see if ROM EP is good if(rom_size <= 0x200 || strncmp((char *)rom_data, "Pico", 4) == 0 || - ((*(unsigned short *)(rom_data+4)<<16)|(*(unsigned short *)(rom_data+6))) >= (int)rom_size) { + ((*(unsigned char *)(rom_data+4)<<16)|(*(unsigned short *)(rom_data+6))) >= (int)rom_size) { if (rom_data) free(rom_data); rom_data = 0; sprintf(menuErrorMsg, "Not a ROM selected."); @@ -393,6 +385,9 @@ int emu_ReloadRom(void) } +static void emu_msg_cb(const char *msg); +static void emu_msg_tray_open(void); + void emu_Init(void) { // make temp buffer for alt renderer @@ -409,8 +404,9 @@ void emu_Init(void) mkdir("cfg", 0777); PicoInit(); - -// logf = fopen("log.txt", "w"); + PicoMessage = emu_msg_cb; + PicoMCDopenTray = emu_msg_tray_open; + PicoMCDcloseTray = menu_loop_tray; } @@ -463,6 +459,18 @@ static void find_combos(void) } +void scaling_update(void) +{ + PicoOpt &= ~0x4100; + switch (currentConfig.scaling) { + default: break; // off + case 1: // hw hor + case 2: PicoOpt |= 0x0100; break; // hw hor+vert + case 3: PicoOpt |= 0x4000; break; // sw hor + } +} + + int emu_ReadConfig(int game) { FILE *f; @@ -474,8 +482,8 @@ int emu_ReadConfig(int game) // set default config memset(¤tConfig, 0, sizeof(currentConfig)); currentConfig.lastRomFile[0] = 0; - currentConfig.EmuOpt = 0x1f | 0x400; // | cd_leds - currentConfig.PicoOpt = 0x0f | 0xe00; // | use_940 | cd_pcm | cd_cdda + currentConfig.EmuOpt = 0x1f | 0x600; // | confirm_save, cd_leds + currentConfig.PicoOpt = 0x0f | 0xe00; // | use_940, cd_pcm, cd_cdda currentConfig.PsndRate = 22050; // 44100; currentConfig.PicoRegion = 0; // auto currentConfig.PicoAutoRgnOrder = 0x184; // US, EU, JP @@ -497,6 +505,7 @@ int emu_ReadConfig(int game) currentConfig.KeyBinds[22] = 1<<30; // vol down currentConfig.gamma = 100; currentConfig.PicoCDBuffers = 64; + currentConfig.scaling = 0; strncpy(cfg, PicoConfigFile, 511); cfg[511] = 0; } else { @@ -512,7 +521,7 @@ int emu_ReadConfig(int game) bread = fread(¤tConfig, 1, sizeof(currentConfig), f); fclose(f); } - printf((bread == sizeof(currentConfig)) ? "(ok)\n" : "(failed)\n"); + printf(bread > 0 ? "(ok)\n" : "(failed)\n"); PicoOpt = currentConfig.PicoOpt; PsndRate = currentConfig.PsndRate; @@ -523,16 +532,18 @@ int emu_ReadConfig(int game) actionNames[ 8] = "Z"; actionNames[ 9] = "Y"; actionNames[10] = "X"; actionNames[11] = "MODE"; } + scaling_update(); // some sanity checks - if (currentConfig.CPUclock < 1 || currentConfig.CPUclock > 4096) currentConfig.CPUclock = 200; + if (currentConfig.CPUclock < 10 || currentConfig.CPUclock > 4096) currentConfig.CPUclock = 200; if (currentConfig.gamma < 10 || currentConfig.gamma > 300) currentConfig.gamma = 100; + if (currentConfig.volume < 0 || currentConfig.volume > 99) currentConfig.volume = 50; // if volume keys are unbound, bind them to volume control if (!currentConfig.KeyBinds[23] && !currentConfig.KeyBinds[22]) { currentConfig.KeyBinds[23] = 1<<29; // vol up currentConfig.KeyBinds[22] = 1<<30; // vol down } - return (bread == sizeof(currentConfig)); + return (bread > 0); // == sizeof(currentConfig)); } @@ -561,7 +572,9 @@ int emu_WriteConfig(int game) bwrite = fwrite(¤tConfig, 1, sizeof(currentConfig), f); fflush(f); fclose(f); +#ifndef NO_SYNC sync(); +#endif } printf((bwrite == sizeof(currentConfig)) ? "(ok)\n" : "(failed)\n"); @@ -577,12 +590,26 @@ void emu_Deinit(void) SRam.changed = 0; } - if (!(currentConfig.EmuOpt & 0x20)) - emu_WriteConfig(0); + if (!(currentConfig.EmuOpt & 0x20)) { + FILE *f = fopen(PicoConfigFile, "r+b"); + if (!f) emu_WriteConfig(0); + else { + // if we already have config, reload it, except last ROM + fseek(f, sizeof(currentConfig.lastRomFile), SEEK_SET); + fread(¤tConfig.EmuOpt, 1, sizeof(currentConfig) - sizeof(currentConfig.lastRomFile), f); + fseek(f, 0, SEEK_SET); + fwrite(¤tConfig, 1, sizeof(currentConfig), f); + fflush(f); + fclose(f); +#ifndef NO_SYNC + sync(); +#endif + } + } + free(framebuff); PicoExit(); -// fclose(logf); // restore gamma if (gp2x_old_gamma != 100) @@ -702,9 +729,13 @@ static void blit(const char *fps, const char *notice) } } - if (notice) osd_text(4, 232, notice); - if (emu_opt & 2) - osd_text(osd_fps_x, 232, fps); + if (notice || (emu_opt & 2)) { + int h = 232; + if (currentConfig.scaling == 2 && !(Pico.video.reg[1]&8)) h -= 8; + if (notice) osd_text(4, h, notice); + if (emu_opt & 2) + osd_text(osd_fps_x, h, fps); + } if ((emu_opt & 0x400) && (PicoMCD & 1)) cd_leds(); @@ -767,23 +798,53 @@ static void vidResetMode(void) } Pico.m.dirtyPal = 1; // reset scaling - gp2x_video_RGB_setscaling((PicoOpt&0x100)&&!(Pico.video.reg[12]&1) ? 256 : 320, 240); + if (currentConfig.scaling == 2 && !(Pico.video.reg[1]&8)) + gp2x_video_RGB_setscaling(8, (PicoOpt&0x100)&&!(Pico.video.reg[12]&1) ? 256 : 320, 224); + else gp2x_video_RGB_setscaling(0, (PicoOpt&0x100)&&!(Pico.video.reg[12]&1) ? 256 : 320, 240); } +static void emu_msg_cb(const char *msg) +{ + if ((PicoOpt&0x10)||!(currentConfig.EmuOpt&0x80)) { + // 8-bit renderers + gp2x_memset_all_buffers(320*232, 0xe0, 320*8); + osd_text(4, 232, msg); + gp2x_memcpy_all_buffers((char *)gp2x_screen+320*232, 320*232, 320*8); + } else { + // 16bit accurate renderer + gp2x_memset_all_buffers(320*232*2, 0, 320*8*2); + osd_text(4, 232, msg); + gp2x_memcpy_all_buffers((char *)gp2x_screen+320*232*2, 320*232*2, 320*8*2); + } + gettimeofday(¬iceMsgTime, 0); + noticeMsgTime.tv_sec -= 2; + + /* assumption: emu_msg_cb gets called only when something slow is about to happen */ + reset_timing = 1; +} + static void emu_state_cb(const char *str) { clearArea(0); blit("", str); } +static void emu_msg_tray_open(void) +{ + strcpy(noticeMsg, "CD tray opened"); + gettimeofday(¬iceMsgTime, 0); +} + static void RunEvents(unsigned int which) { if(which & 0x1800) { // save or load (but not both) int do_it = 1; - if (!(which & 0x1000) && (currentConfig.EmuOpt & 0x200) && emu_check_save_file(state_slot)) { + if ( emu_check_save_file(state_slot) && + (( (which & 0x1000) && (currentConfig.EmuOpt & 0x800)) || // load + (!(which & 0x1000) && (currentConfig.EmuOpt & 0x200))) ) { // save unsigned long keys; - blit("", "OVERWRITE SAVE? (Y=yes, X=no)"); + blit("", (which & 0x1000) ? "LOAD STATE? (Y=yes, X=no)" : "OVERWRITE SAVE? (Y=yes, X=no)"); while( !((keys = gp2x_joystick_read(1)) & (GP2X_X|GP2X_Y)) ) usleep(50*1024); if (keys & GP2X_X) do_it = 0; @@ -927,7 +988,7 @@ static void updateKeys(void) if(events & 0x6000) { int vol = currentConfig.volume; if (events & 0x2000) { - if (vol < 90) vol++; + if (vol < 99) vol++; } else { if (vol > 0) vol--; } @@ -949,25 +1010,17 @@ static void updateSound(int len) { if (PicoOpt&8) len<<=1; - gp2x_sound_write(PsndOut, len<<1); + /* avoid writing audio when lagging behind to prevent audio lag */ + if (PicoSkipFrame != 2) + gp2x_sound_write(PsndOut, len<<1); } -static void SkipFrame(int do_sound) +static void SkipFrame(int do_audio) { - void *sndbuff_tmp = 0; - if (PsndOut && !do_sound) { - sndbuff_tmp = PsndOut; - PsndOut = 0; - } - - PicoSkipFrame=1; + PicoSkipFrame=do_audio ? 1 : 2; PicoFrame(); PicoSkipFrame=0; - - if (sndbuff_tmp && !do_sound) { - PsndOut = sndbuff_tmp; - } } @@ -977,7 +1030,6 @@ void emu_forced_frame(void) PicoOpt |= 0x10; PicoFrameFull(); - PicoOpt = po_old; if (!(Pico.video.reg[12]&1)) { vidCpyM2 = vidCpyM2_32col; @@ -987,6 +1039,8 @@ void emu_forced_frame(void) vidCpyM2((unsigned char *)gp2x_screen+320*8, framebuff+328*8); vidConvCpyRGB32(localPal, Pico.cram, 0x40); gp2x_video_setpalette(localPal, 0x40); + + PicoOpt = po_old; } static void simpleWait(int thissec, int lim_time) @@ -1116,7 +1170,9 @@ void emu_Loop(void) vidCpyM2 = vidCpyM2_32col; } } - gp2x_video_RGB_setscaling(scalex, 240); + if (currentConfig.scaling == 2 && !(modes&8)) // want vertical scaling and game is not in 240 line mode + gp2x_video_RGB_setscaling(8, scalex, 224); + else gp2x_video_RGB_setscaling(0, scalex, 240); oldmodes = modes; clearArea(1); } @@ -1154,7 +1210,9 @@ void emu_Loop(void) if (frames_shown > frames_done) frames_shown = frames_done; } } - +#if 0 + sprintf(fpsbuff, "%05i", Pico.m.frame_count); +#endif lim_time = (frames_done+1) * target_frametime; if(currentConfig.Frameskip >= 0) { // frameskip enabled for(i = 0; i < currentConfig.Frameskip; i++) { @@ -1171,8 +1229,14 @@ void emu_Loop(void) } } else if(tval.tv_usec > lim_time) { // auto frameskip // no time left for this frame - skip + if (tval.tv_usec - lim_time >= 0x300000) { + /* something caused a slowdown for us (disk access? cache flush?) + * try to recover by resetting timing... */ + reset_timing = 1; + continue; + } updateKeys(); - SkipFrame(tval.tv_usec < lim_time+target_frametime); frames_done++; + SkipFrame(tval.tv_usec < lim_time+target_frametime*2); frames_done++; continue; } @@ -1239,14 +1303,14 @@ if (Pico.m.frame_count == 31563) { // check time gettimeofday(&tval, 0); - if(thissec != tval.tv_sec) tval.tv_usec+=1000000; + if (thissec != tval.tv_sec) tval.tv_usec+=1000000; - // sleep if we are still too fast - if(PsndOut != 0 || currentConfig.Frameskip < 0) + if (currentConfig.Frameskip < 0 && tval.tv_usec - lim_time >= 0x300000) // slowdown detection + reset_timing = 1; + else if (PsndOut != NULL || currentConfig.Frameskip < 0) { + // sleep if we are still too fast // usleep sleeps for ~20ms minimum, so it is not a solution here - gettimeofday(&tval, 0); - if(thissec != tval.tv_sec) tval.tv_usec+=1000000; if(tval.tv_usec < lim_time) { // we are too fast @@ -1264,7 +1328,7 @@ if (Pico.m.frame_count == 31563) { // save SRAM if((currentConfig.EmuOpt & 1) && SRam.changed) { - osd_text(4, 232, "Writing SRAM/BRAM.."); + emu_state_cb("Writing SRAM/BRAM.."); emu_SaveLoadGame(0, 1); SRam.changed = 0; } @@ -1395,33 +1459,48 @@ int emu_SaveLoadGame(int load, int sram) FILE *sramFile; int sram_size; unsigned char *sram_data; + int truncate = 1; if (PicoMCD&1) { - sram_size = 0x2000; - sram_data = Pico_mcd->bram; + if (PicoOpt&0x8000) { // MCD RAM cart? + sram_size = 0x12000; + sram_data = SRam.data; + if (sram_data) + memcpy32((int *)sram_data, (int *)Pico_mcd->bram, 0x2000/4); + } else { + sram_size = 0x2000; + sram_data = Pico_mcd->bram; + truncate = 0; // the .brm may contain RAM cart data after normal brm + } } else { sram_size = SRam.end-SRam.start+1; if(SRam.reg_back & 4) sram_size=0x2000; sram_data = SRam.data; } - if(!sram_data) return 0; // SRam forcefully disabled for this game + if (!sram_data) return 0; // SRam forcefully disabled for this game - if(load) { + if (load) { sramFile = fopen(saveFname, "rb"); if(!sramFile) return -1; fread(sram_data, 1, sram_size, sramFile); fclose(sramFile); + if ((PicoMCD&1) && (PicoOpt&0x8000)) + memcpy32((int *)Pico_mcd->bram, (int *)sram_data, 0x2000/4); } else { // sram save needs some special processing // see if we have anything to save - for(; sram_size > 0; sram_size--) - if(sram_data[sram_size-1]) break; + for (; sram_size > 0; sram_size--) + if (sram_data[sram_size-1]) break; - if(sram_size) { - sramFile = fopen(saveFname, "wb"); + if (sram_size) { + sramFile = fopen(saveFname, truncate ? "wb" : "r+b"); + if (!sramFile) sramFile = fopen(saveFname, "wb"); // retry + if (!sramFile) return -1; ret = fwrite(sram_data, 1, sram_size, sramFile); ret = (ret != sram_size) ? -1 : 0; fclose(sramFile); +#ifndef NO_SYNC sync(); +#endif } } return ret; @@ -1445,8 +1524,10 @@ int emu_SaveLoadGame(int load, int sram) ret = PmovState(load ? 6 : 5, PmovFile); areaClose(PmovFile); PmovFile = 0; - if (!load) sync(); - else Pico.m.dirtyPal=1; + if (load) Pico.m.dirtyPal=1; +#ifndef NO_SYNC + else sync(); +#endif } else ret = -1; if (!ret)