emu.c 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642
  1. // (c) Copyright 2006-2007 notaz, All rights reserved.
  2. // Free for non-commercial use.
  3. // For commercial use, separate licencing terms must be obtained.
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <sys/time.h>
  7. #include <sys/stat.h>
  8. #include <sys/types.h>
  9. #include <linux/limits.h>
  10. #include <ctype.h>
  11. #include <unistd.h>
  12. #include <stdarg.h>
  13. #include "emu.h"
  14. #include "gp2x.h"
  15. #include "usbjoy.h"
  16. #include "menu.h"
  17. #include "asmutils.h"
  18. #include "cpuctrl.h"
  19. #include "fonts.h"
  20. #include <Pico/PicoInt.h>
  21. #include <Pico/Patch.h>
  22. #include <zlib/zlib.h>
  23. #ifdef BENCHMARK
  24. #define OSD_FPS_X 220
  25. #else
  26. #define OSD_FPS_X 260
  27. #endif
  28. int engineState;
  29. int select_exits = 0;
  30. char *PicoConfigFile = "picoconfig.bin";
  31. currentConfig_t currentConfig;
  32. char romFileName[PATH_MAX];
  33. unsigned char *rom_data = NULL;
  34. extern int crashed_940;
  35. static short sndBuffer[2*44100/50];
  36. static char noticeMsg[64]; // notice msg to draw
  37. static struct timeval noticeMsgTime = { 0, 0 }; // when started showing
  38. static int osd_fps_x;
  39. static int combo_keys = 0, combo_acts = 0; // keys and actions which need button combos
  40. static int gp2x_old_gamma = 100;
  41. static unsigned char *movie_data = NULL;
  42. static int movie_size = 0;
  43. unsigned char *framebuff = 0; // temporary buffer for alt renderer
  44. int state_slot = 0;
  45. int reset_timing = 0;
  46. int config_slot = 0, config_slot_current = 0;
  47. // utilities
  48. static void strlwr(char* string)
  49. {
  50. while ( (*string++ = (char)tolower(*string)) );
  51. }
  52. static int try_rfn_cut(void)
  53. {
  54. FILE *tmp;
  55. char *p;
  56. p = romFileName + strlen(romFileName) - 1;
  57. for (; p > romFileName; p--)
  58. if (*p == '.') break;
  59. *p = 0;
  60. if((tmp = fopen(romFileName, "rb"))) {
  61. fclose(tmp);
  62. return 1;
  63. }
  64. return 0;
  65. }
  66. static void get_ext(char *file, char *ext)
  67. {
  68. char *p;
  69. p = file + strlen(file) - 4;
  70. if (p < file) p = file;
  71. strncpy(ext, p, 4);
  72. ext[4] = 0;
  73. strlwr(ext);
  74. }
  75. char *biosfiles_us[] = { "us_scd2_9306", "SegaCDBIOS9303", "us_scd1_9210" };
  76. char *biosfiles_eu[] = { "eu_mcd2_9306", "eu_mcd2_9303", "eu_mcd1_9210" };
  77. char *biosfiles_jp[] = { "jp_mcd1_9112", "jp_mcd1_9111" };
  78. extern char **g_argv;
  79. int find_bios(int region, char **bios_file)
  80. {
  81. static char bios_path[1024];
  82. int i, j, count;
  83. char **files;
  84. FILE *f = NULL;
  85. if (region == 4) { // US
  86. files = biosfiles_us;
  87. count = sizeof(biosfiles_us) / sizeof(char *);
  88. } else if (region == 8) { // EU
  89. files = biosfiles_eu;
  90. count = sizeof(biosfiles_eu) / sizeof(char *);
  91. } else if (region == 1 || region == 2) {
  92. files = biosfiles_jp;
  93. count = sizeof(biosfiles_jp) / sizeof(char *);
  94. } else {
  95. return 0;
  96. }
  97. for (i = 0; i < count; i++)
  98. {
  99. strncpy(bios_path, g_argv[0], 1023);
  100. bios_path[1024-32] = 0;
  101. for (j = strlen(bios_path); j > 0; j--)
  102. if (bios_path[j] == '/') { bios_path[j+1] = 0; break; }
  103. strcat(bios_path, files[i]);
  104. strcat(bios_path, ".bin");
  105. f = fopen(bios_path, "rb");
  106. if (f) break;
  107. bios_path[strlen(bios_path) - 4] = 0;
  108. strcat(bios_path, ".zip");
  109. f = fopen(bios_path, "rb");
  110. if (f) break;
  111. }
  112. if (f) {
  113. printf("using bios: %s\n", bios_path);
  114. fclose(f);
  115. if (bios_file) *bios_file = bios_path;
  116. return 1;
  117. } else {
  118. sprintf(menuErrorMsg, "no %s BIOS files found, read docs",
  119. region != 4 ? (region == 8 ? "EU" : "JAP") : "USA");
  120. printf("%s\n", menuErrorMsg);
  121. return 0;
  122. }
  123. }
  124. /* checks if romFileName points to valid MegaCD image
  125. * if so, checks for suitable BIOS */
  126. int emu_cd_check(char **bios_file)
  127. {
  128. unsigned char buf[32];
  129. pm_file *cd_f;
  130. int type = 0, region = 4; // 1: Japan, 4: US, 8: Europe
  131. cd_f = pm_open(romFileName);
  132. if (!cd_f) return 0; // let the upper level handle this
  133. if (pm_read(buf, 32, cd_f) != 32) {
  134. pm_close(cd_f);
  135. return 0;
  136. }
  137. if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x00, 14)) type = 1; // Sega CD (ISO)
  138. if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x10, 14)) type = 2; // Sega CD (BIN)
  139. if (type == 0) {
  140. pm_close(cd_f);
  141. return 0;
  142. }
  143. /* it seems we have a CD image here. Try to detect region now.. */
  144. pm_seek(cd_f, (type == 1) ? 0x100+0x10B : 0x110+0x10B, SEEK_SET);
  145. pm_read(buf, 1, cd_f);
  146. pm_close(cd_f);
  147. if (buf[0] == 0x64) region = 8; // EU
  148. if (buf[0] == 0xa1) region = 1; // JAP
  149. printf("detected %s Sega/Mega CD image with %s region\n",
  150. type == 2 ? "BIN" : "ISO", region != 4 ? (region == 8 ? "EU" : "JAP") : "USA");
  151. if (PicoRegionOverride) {
  152. region = PicoRegionOverride;
  153. printf("overrided region to %s\n", region != 4 ? (region == 8 ? "EU" : "JAP") : "USA");
  154. }
  155. if (bios_file == NULL) return type;
  156. if (find_bios(region, bios_file))
  157. return type; // CD and BIOS detected
  158. return -1; // CD detected but load failed
  159. }
  160. int emu_ReloadRom(void)
  161. {
  162. unsigned int rom_size = 0;
  163. char *used_rom_name = romFileName;
  164. char ext[5];
  165. pm_file *rom;
  166. int ret, cd_state;
  167. printf("emu_ReloadRom(%s)\n", romFileName);
  168. get_ext(romFileName, ext);
  169. // detect wrong extensions
  170. if(!strcmp(ext, ".srm") || !strcmp(ext, "s.gz") || !strcmp(ext, ".mds")) { // s.gz ~ .mds.gz
  171. sprintf(menuErrorMsg, "Not a ROM selected.");
  172. return 0;
  173. }
  174. PicoPatchUnload();
  175. // check for movie file
  176. if(movie_data) {
  177. free(movie_data);
  178. movie_data = 0;
  179. }
  180. if(!strcmp(ext, ".gmv")) {
  181. // check for both gmv and rom
  182. int dummy;
  183. FILE *movie_file = fopen(romFileName, "rb");
  184. if(!movie_file) {
  185. sprintf(menuErrorMsg, "Failed to open movie.");
  186. return 0;
  187. }
  188. fseek(movie_file, 0, SEEK_END);
  189. movie_size = ftell(movie_file);
  190. fseek(movie_file, 0, SEEK_SET);
  191. if(movie_size < 64+3) {
  192. sprintf(menuErrorMsg, "Invalid GMV file.");
  193. fclose(movie_file);
  194. return 0;
  195. }
  196. movie_data = malloc(movie_size);
  197. if(movie_data == NULL) {
  198. sprintf(menuErrorMsg, "low memory.");
  199. fclose(movie_file);
  200. return 0;
  201. }
  202. fread(movie_data, 1, movie_size, movie_file);
  203. fclose(movie_file);
  204. if (strncmp((char *)movie_data, "Gens Movie TEST", 15) != 0) {
  205. sprintf(menuErrorMsg, "Invalid GMV file.");
  206. return 0;
  207. }
  208. dummy = try_rfn_cut() || try_rfn_cut();
  209. if (!dummy) {
  210. sprintf(menuErrorMsg, "Could't find a ROM for movie.");
  211. return 0;
  212. }
  213. get_ext(romFileName, ext);
  214. }
  215. else if (!strcmp(ext, ".pat")) {
  216. int dummy;
  217. PicoPatchLoad(romFileName);
  218. dummy = try_rfn_cut() || try_rfn_cut();
  219. if (!dummy) {
  220. sprintf(menuErrorMsg, "Could't find a ROM to patch.");
  221. return 0;
  222. }
  223. get_ext(romFileName, ext);
  224. }
  225. if ((PicoMCD & 1) && Pico_mcd != NULL)
  226. Stop_CD();
  227. // check for MegaCD image
  228. cd_state = emu_cd_check(&used_rom_name);
  229. if (cd_state > 0) {
  230. PicoMCD |= 1;
  231. get_ext(used_rom_name, ext);
  232. } else if (cd_state == -1) {
  233. // bios_help() ?
  234. return 0;
  235. } else {
  236. if (PicoMCD & 1) Stop_CD();
  237. PicoMCD &= ~1;
  238. }
  239. rom = pm_open(used_rom_name);
  240. if(!rom) {
  241. sprintf(menuErrorMsg, "Failed to open rom.");
  242. return 0;
  243. }
  244. menu_romload_prepare(used_rom_name);
  245. if(rom_data) {
  246. free(rom_data);
  247. rom_data = 0;
  248. rom_size = 0;
  249. }
  250. if( (ret = PicoCartLoad(rom, &rom_data, &rom_size)) ) {
  251. sprintf(menuErrorMsg, "PicoCartLoad() failed.");
  252. printf("%s\n", menuErrorMsg);
  253. pm_close(rom);
  254. menu_romload_end();
  255. return 0;
  256. }
  257. pm_close(rom);
  258. menu_romload_end();
  259. // detect wrong files (Pico crashes on very small files), also see if ROM EP is good
  260. if(rom_size <= 0x200 || strncmp((char *)rom_data, "Pico", 4) == 0 ||
  261. ((*(unsigned char *)(rom_data+4)<<16)|(*(unsigned short *)(rom_data+6))) >= (int)rom_size) {
  262. if (rom_data) free(rom_data);
  263. rom_data = 0;
  264. sprintf(menuErrorMsg, "Not a ROM selected.");
  265. return 0;
  266. }
  267. // load config for this ROM (do this before insert to get correct region)
  268. ret = emu_ReadConfig(1, 1);
  269. if (!ret)
  270. emu_ReadConfig(0, 1);
  271. printf("PicoCartInsert(%p, %d);\n", rom_data, rom_size);
  272. if(PicoCartInsert(rom_data, rom_size)) {
  273. sprintf(menuErrorMsg, "Failed to load ROM.");
  274. return 0;
  275. }
  276. Pico.m.frame_count = 0;
  277. // insert CD if it was detected
  278. if (cd_state > 0) {
  279. ret = Insert_CD(romFileName, cd_state == 2);
  280. if (ret != 0) {
  281. sprintf(menuErrorMsg, "Insert_CD() failed, invalid CD image?");
  282. printf("%s\n", menuErrorMsg);
  283. return 0;
  284. }
  285. }
  286. // emu_ReadConfig() might have messed currentConfig.lastRomFile
  287. strncpy(currentConfig.lastRomFile, romFileName, sizeof(currentConfig.lastRomFile)-1);
  288. currentConfig.lastRomFile[sizeof(currentConfig.lastRomFile)-1] = 0;
  289. if (PicoPatches) {
  290. PicoPatchPrepare();
  291. PicoPatchApply();
  292. }
  293. // additional movie stuff
  294. if(movie_data) {
  295. if(movie_data[0x14] == '6')
  296. PicoOpt |= 0x20; // 6 button pad
  297. else PicoOpt &= ~0x20;
  298. PicoOpt |= 0x40; // accurate timing
  299. if(movie_data[0xF] >= 'A') {
  300. if(movie_data[0x16] & 0x80) {
  301. PicoRegionOverride = 8;
  302. } else {
  303. PicoRegionOverride = 4;
  304. }
  305. PicoReset(0);
  306. // TODO: bits 6 & 5
  307. }
  308. movie_data[0x18+30] = 0;
  309. sprintf(noticeMsg, "MOVIE: %s", (char *) &movie_data[0x18]);
  310. }
  311. else
  312. {
  313. if(Pico.m.pal) {
  314. strcpy(noticeMsg, "PAL SYSTEM / 50 FPS");
  315. } else {
  316. strcpy(noticeMsg, "NTSC SYSTEM / 60 FPS");
  317. }
  318. }
  319. gettimeofday(&noticeMsgTime, 0);
  320. // load SRAM for this ROM
  321. if(currentConfig.EmuOpt & 1)
  322. emu_SaveLoadGame(1, 1);
  323. return 1;
  324. }
  325. static void emu_msg_cb(const char *msg);
  326. static void emu_msg_tray_open(void);
  327. void emu_Init(void)
  328. {
  329. // make temp buffer for alt renderer
  330. framebuff = malloc((8+320)*(8+240+8));
  331. if (!framebuff)
  332. {
  333. printf("framebuff == 0\n");
  334. }
  335. // make dirs for saves, cfgs, etc.
  336. mkdir("mds", 0777);
  337. mkdir("srm", 0777);
  338. mkdir("brm", 0777);
  339. mkdir("cfg", 0777);
  340. PicoInit();
  341. PicoMessage = emu_msg_cb;
  342. PicoMCDopenTray = emu_msg_tray_open;
  343. PicoMCDcloseTray = menu_loop_tray;
  344. }
  345. static void romfname_ext(char *dst, const char *prefix, const char *ext)
  346. {
  347. char *p;
  348. int prefix_len = 0;
  349. // make save filename
  350. for (p = romFileName+strlen(romFileName)-1; p >= romFileName && *p != '/'; p--); p++;
  351. *dst = 0;
  352. if (prefix) {
  353. strcpy(dst, prefix);
  354. prefix_len = strlen(prefix);
  355. }
  356. strncpy(dst + prefix_len, p, 511-prefix_len);
  357. dst[511-8] = 0;
  358. if (dst[strlen(dst)-4] == '.') dst[strlen(dst)-4] = 0;
  359. if (ext) strcat(dst, ext);
  360. }
  361. static void find_combos(void)
  362. {
  363. int act, u;
  364. // find out which keys and actions are combos
  365. combo_keys = combo_acts = 0;
  366. for (act = 0; act < 32; act++)
  367. {
  368. int keyc = 0;
  369. if (act == 16) continue; // player2 flag
  370. for (u = 0; u < 32; u++)
  371. {
  372. if (currentConfig.KeyBinds[u] & (1 << act)) keyc++;
  373. }
  374. if (keyc > 1)
  375. {
  376. // loop again and mark those keys and actions as combo
  377. for (u = 0; u < 32; u++)
  378. {
  379. if (currentConfig.KeyBinds[u] & (1 << act)) {
  380. combo_keys |= 1 << u;
  381. combo_acts |= 1 << act;
  382. }
  383. }
  384. }
  385. }
  386. // printf("combo keys/acts: %08x %08x\n", combo_keys, combo_acts);
  387. }
  388. void scaling_update(void)
  389. {
  390. PicoOpt &= ~0x4100;
  391. switch (currentConfig.scaling) {
  392. default: break; // off
  393. case 1: // hw hor
  394. case 2: PicoOpt |= 0x0100; break; // hw hor+vert
  395. case 3: PicoOpt |= 0x4000; break; // sw hor
  396. }
  397. }
  398. int emu_ReadConfig(int game, int no_defaults)
  399. {
  400. FILE *f;
  401. char cfg[512], extbuf[16];
  402. int bread = 0;
  403. if (!game)
  404. {
  405. if (!no_defaults)
  406. {
  407. // set default config
  408. memset(&currentConfig, 0, sizeof(currentConfig));
  409. currentConfig.lastRomFile[0] = 0;
  410. currentConfig.EmuOpt = 0x1f | 0x600; // | confirm_save, cd_leds
  411. currentConfig.PicoOpt = 0x0f | 0xe00; // | use_940, cd_pcm, cd_cdda
  412. currentConfig.PsndRate = 22050; // 44100;
  413. currentConfig.PicoRegion = 0; // auto
  414. currentConfig.PicoAutoRgnOrder = 0x184; // US, EU, JP
  415. currentConfig.Frameskip = -1; // auto
  416. currentConfig.CPUclock = 200;
  417. currentConfig.volume = 50;
  418. currentConfig.KeyBinds[ 0] = 1<<0; // SACB RLDU
  419. currentConfig.KeyBinds[ 4] = 1<<1;
  420. currentConfig.KeyBinds[ 2] = 1<<2;
  421. currentConfig.KeyBinds[ 6] = 1<<3;
  422. currentConfig.KeyBinds[14] = 1<<4;
  423. currentConfig.KeyBinds[13] = 1<<5;
  424. currentConfig.KeyBinds[12] = 1<<6;
  425. currentConfig.KeyBinds[ 8] = 1<<7;
  426. currentConfig.KeyBinds[15] = 1<<26; // switch rend
  427. currentConfig.KeyBinds[10] = 1<<27; // save state
  428. currentConfig.KeyBinds[11] = 1<<28; // load state
  429. currentConfig.KeyBinds[23] = 1<<29; // vol up
  430. currentConfig.KeyBinds[22] = 1<<30; // vol down
  431. currentConfig.gamma = 100;
  432. currentConfig.PicoCDBuffers = 64;
  433. currentConfig.scaling = 0;
  434. }
  435. strncpy(cfg, PicoConfigFile, 511);
  436. if (config_slot != 0)
  437. {
  438. char *p = strrchr(cfg, '.');
  439. if (p == NULL) p = cfg + strlen(cfg);
  440. sprintf(extbuf, ".%i.pbcfg", config_slot);
  441. strncpy(p, extbuf, 511 - (p - cfg));
  442. }
  443. cfg[511] = 0;
  444. } else {
  445. if (config_slot != 0)
  446. sprintf(extbuf, ".%i.pbcfg", config_slot);
  447. else strcpy(extbuf, ".pbcfg");
  448. romfname_ext(cfg, "cfg/", extbuf);
  449. f = fopen(cfg, "rb");
  450. if (!f) romfname_ext(cfg, NULL, ".pbcfg");
  451. else fclose(f);
  452. }
  453. printf("emu_ReadConfig: %s ", cfg);
  454. f = fopen(cfg, "rb");
  455. if (f) {
  456. bread = fread(&currentConfig, 1, sizeof(currentConfig), f);
  457. fclose(f);
  458. }
  459. printf(bread > 0 ? "(ok)\n" : "(failed)\n");
  460. PicoOpt = currentConfig.PicoOpt;
  461. PsndRate = currentConfig.PsndRate;
  462. PicoRegionOverride = currentConfig.PicoRegion;
  463. PicoAutoRgnOrder = currentConfig.PicoAutoRgnOrder;
  464. PicoCDBuffers = currentConfig.PicoCDBuffers;
  465. scaling_update();
  466. // some sanity checks
  467. if (currentConfig.CPUclock < 10 || currentConfig.CPUclock > 4096) currentConfig.CPUclock = 200;
  468. if (currentConfig.gamma < 10 || currentConfig.gamma > 300) currentConfig.gamma = 100;
  469. if (currentConfig.volume < 0 || currentConfig.volume > 99) currentConfig.volume = 50;
  470. // if volume keys are unbound, bind them to volume control
  471. if (!currentConfig.KeyBinds[23] && !currentConfig.KeyBinds[22]) {
  472. currentConfig.KeyBinds[23] = 1<<29; // vol up
  473. currentConfig.KeyBinds[22] = 1<<30; // vol down
  474. }
  475. if (bread > 0) config_slot_current = config_slot;
  476. return (bread > 0); // == sizeof(currentConfig));
  477. }
  478. int emu_WriteConfig(int game)
  479. {
  480. FILE *f;
  481. char cfg[512], extbuf[16];
  482. int bwrite = 0;
  483. if (!game)
  484. {
  485. strncpy(cfg, PicoConfigFile, 511);
  486. if (config_slot != 0)
  487. {
  488. char *p = strrchr(cfg, '.');
  489. if (p == NULL) p = cfg + strlen(cfg);
  490. sprintf(extbuf, ".%i.pbcfg", config_slot);
  491. strncpy(p, extbuf, 511 - (p - cfg));
  492. }
  493. cfg[511] = 0;
  494. } else {
  495. if (config_slot != 0)
  496. sprintf(extbuf, ".%i.pbcfg", config_slot);
  497. else strcpy(extbuf, ".pbcfg");
  498. romfname_ext(cfg, "cfg/", extbuf);
  499. }
  500. printf("emu_WriteConfig: %s ", cfg);
  501. f = fopen(cfg, "wb");
  502. if (f) {
  503. currentConfig.PicoOpt = PicoOpt;
  504. currentConfig.PsndRate = PsndRate;
  505. currentConfig.PicoRegion = PicoRegionOverride;
  506. currentConfig.PicoAutoRgnOrder = PicoAutoRgnOrder;
  507. currentConfig.PicoCDBuffers = PicoCDBuffers;
  508. bwrite = fwrite(&currentConfig, 1, sizeof(currentConfig), f);
  509. fflush(f);
  510. fclose(f);
  511. #ifndef NO_SYNC
  512. sync();
  513. #endif
  514. }
  515. printf((bwrite == sizeof(currentConfig)) ? "(ok)\n" : "(failed)\n");
  516. if (bwrite == sizeof(currentConfig)) config_slot_current = config_slot;
  517. return (bwrite == sizeof(currentConfig));
  518. }
  519. void emu_Deinit(void)
  520. {
  521. // save SRAM
  522. if((currentConfig.EmuOpt & 1) && SRam.changed) {
  523. emu_SaveLoadGame(0, 1);
  524. SRam.changed = 0;
  525. }
  526. if (!(currentConfig.EmuOpt & 0x20)) {
  527. FILE *f = fopen(PicoConfigFile, "r+b");
  528. if (!f) emu_WriteConfig(0);
  529. else {
  530. // if we already have config, reload it, except last ROM
  531. fseek(f, sizeof(currentConfig.lastRomFile), SEEK_SET);
  532. fread(&currentConfig.EmuOpt, 1, sizeof(currentConfig) - sizeof(currentConfig.lastRomFile), f);
  533. fseek(f, 0, SEEK_SET);
  534. fwrite(&currentConfig, 1, sizeof(currentConfig), f);
  535. fflush(f);
  536. fclose(f);
  537. #ifndef NO_SYNC
  538. sync();
  539. #endif
  540. }
  541. }
  542. free(framebuff);
  543. PicoExit();
  544. // restore gamma
  545. if (gp2x_old_gamma != 100)
  546. set_gamma(100, 0);
  547. }
  548. static void text_out8_builtin(int x, int y, const char *text)
  549. {
  550. int i,l,len=strlen(text);
  551. unsigned char *screen = (unsigned char *)gp2x_screen + x + y*320;
  552. /* always using built-in font */
  553. for (i = 0; i < len; i++)
  554. {
  555. for (l=0;l<8;l++)
  556. {
  557. unsigned char fd = fontdata8x8[((text[i])*8)+l];
  558. if (fd&0x80) screen[l*320+0]=0xf0;
  559. if (fd&0x40) screen[l*320+1]=0xf0;
  560. if (fd&0x20) screen[l*320+2]=0xf0;
  561. if (fd&0x10) screen[l*320+3]=0xf0;
  562. if (fd&0x08) screen[l*320+4]=0xf0;
  563. if (fd&0x04) screen[l*320+5]=0xf0;
  564. if (fd&0x02) screen[l*320+6]=0xf0;
  565. if (fd&0x01) screen[l*320+7]=0xf0;
  566. }
  567. screen += 8;
  568. }
  569. }
  570. static void text_out16_builtin(int x, int y, const char *text)
  571. {
  572. int i,l,len=strlen(text);
  573. unsigned short *screen = (unsigned short *)gp2x_screen + x + y*320;
  574. for (i = 0; i < len; i++)
  575. {
  576. for (l=0;l<8;l++)
  577. {
  578. unsigned char fd = fontdata8x8[((text[i])*8)+l];
  579. if(fd&0x80) screen[l*320+0]=0xffff;
  580. if(fd&0x40) screen[l*320+1]=0xffff;
  581. if(fd&0x20) screen[l*320+2]=0xffff;
  582. if(fd&0x10) screen[l*320+3]=0xffff;
  583. if(fd&0x08) screen[l*320+4]=0xffff;
  584. if(fd&0x04) screen[l*320+5]=0xffff;
  585. if(fd&0x02) screen[l*320+6]=0xffff;
  586. if(fd&0x01) screen[l*320+7]=0xffff;
  587. }
  588. screen += 8;
  589. }
  590. }
  591. void osd_text(int x, int y, const char *text)
  592. {
  593. int len = strlen(text)*8;
  594. if ((PicoOpt&0x10)||!(currentConfig.EmuOpt&0x80)) {
  595. int *p, i, h;
  596. x &= ~3; // align x
  597. len = (len+3) >> 2;
  598. for (h = 0; h < 8; h++) {
  599. p = (int *) ((unsigned char *) gp2x_screen+x+320*(y+h));
  600. for (i = len; i; i--, p++) *p = 0xe0e0e0e0;
  601. }
  602. text_out8_builtin(x, y, text);
  603. } else {
  604. int *p, i, h;
  605. x &= ~1; // align x
  606. len = (len+1) >> 1;
  607. for (h = 0; h < 8; h++) {
  608. p = (int *) ((unsigned short *) gp2x_screen+x+320*(y+h));
  609. for (i = len; i; i--, p++) *p = (*p>>2)&0x39e7;
  610. }
  611. text_out16_builtin(x, y, text);
  612. }
  613. }
  614. static void cd_leds(void)
  615. {
  616. // mmu problems?
  617. // static
  618. int old_reg;
  619. // if (!((Pico_mcd->s68k_regs[0] ^ old_reg) & 3)) return; // no change
  620. old_reg = Pico_mcd->s68k_regs[0];
  621. if ((PicoOpt&0x10)||!(currentConfig.EmuOpt&0x80)) {
  622. // 8-bit modes
  623. unsigned int col_g = (old_reg & 2) ? 0xc0c0c0c0 : 0xe0e0e0e0;
  624. unsigned int col_r = (old_reg & 1) ? 0xd0d0d0d0 : 0xe0e0e0e0;
  625. *(unsigned int *)((char *)gp2x_screen + 320*2+ 4) =
  626. *(unsigned int *)((char *)gp2x_screen + 320*3+ 4) =
  627. *(unsigned int *)((char *)gp2x_screen + 320*4+ 4) = col_g;
  628. *(unsigned int *)((char *)gp2x_screen + 320*2+12) =
  629. *(unsigned int *)((char *)gp2x_screen + 320*3+12) =
  630. *(unsigned int *)((char *)gp2x_screen + 320*4+12) = col_r;
  631. } else {
  632. // 16-bit modes
  633. unsigned int *p = (unsigned int *)((short *)gp2x_screen + 320*2+4);
  634. unsigned int col_g = (old_reg & 2) ? 0x06000600 : 0;
  635. unsigned int col_r = (old_reg & 1) ? 0xc000c000 : 0;
  636. *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += 320/2 - 12/2;
  637. *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += 320/2 - 12/2;
  638. *p++ = col_g; *p++ = col_g; p+=2; *p++ = col_r; *p++ = col_r; p += 320/2 - 12/2;
  639. }
  640. }
  641. static int EmuScan16(unsigned int num, void *sdata)
  642. {
  643. if (!(Pico.video.reg[1]&8)) num += 8;
  644. DrawLineDest = (unsigned short *) gp2x_screen + 320*(num+1);
  645. return 0;
  646. }
  647. static int EmuScan8(unsigned int num, void *sdata)
  648. {
  649. if (!(Pico.video.reg[1]&8)) num += 8;
  650. DrawLineDest = (unsigned char *) gp2x_screen + 320*(num+1);
  651. return 0;
  652. }
  653. int localPal[0x100];
  654. static void (*vidCpyM2)(void *dest, void *src) = NULL;
  655. static void blit(const char *fps, const char *notice)
  656. {
  657. int emu_opt = currentConfig.EmuOpt;
  658. if (PicoOpt&0x10) {
  659. // 8bit fast renderer
  660. if (Pico.m.dirtyPal) {
  661. Pico.m.dirtyPal = 0;
  662. vidConvCpyRGB32(localPal, Pico.cram, 0x40);
  663. // feed new palette to our device
  664. gp2x_video_setpalette(localPal, 0x40);
  665. }
  666. vidCpyM2((unsigned char *)gp2x_screen+320*8, framebuff+328*8);
  667. } else if (!(emu_opt&0x80)) {
  668. // 8bit accurate renderer
  669. if (Pico.m.dirtyPal) {
  670. Pico.m.dirtyPal = 0;
  671. if(Pico.video.reg[0xC]&8) { // shadow/hilight mode
  672. vidConvCpyRGB32(localPal, Pico.cram, 0x40);
  673. vidConvCpyRGB32sh(localPal+0x40, Pico.cram, 0x40);
  674. vidConvCpyRGB32hi(localPal+0x80, Pico.cram, 0x40);
  675. blockcpy(localPal+0xc0, localPal+0x40, 0x40*4);
  676. localPal[0xc0] = 0x0000c000;
  677. localPal[0xd0] = 0x00c00000;
  678. localPal[0xe0] = 0x00000000; // reserved pixels for OSD
  679. localPal[0xf0] = 0x00ffffff;
  680. gp2x_video_setpalette(localPal, 0x100);
  681. } else if (rendstatus & 0x20) { // mid-frame palette changes
  682. vidConvCpyRGB32(localPal, Pico.cram, 0x40);
  683. vidConvCpyRGB32(localPal+0x40, HighPal, 0x40);
  684. vidConvCpyRGB32(localPal+0x80, HighPal+0x40, 0x40);
  685. gp2x_video_setpalette(localPal, 0xc0);
  686. } else {
  687. vidConvCpyRGB32(localPal, Pico.cram, 0x40);
  688. gp2x_video_setpalette(localPal, 0x40);
  689. }
  690. }
  691. }
  692. if (notice || (emu_opt & 2)) {
  693. int h = 232;
  694. if (currentConfig.scaling == 2 && !(Pico.video.reg[1]&8)) h -= 8;
  695. if (notice) osd_text(4, h, notice);
  696. if (emu_opt & 2)
  697. osd_text(osd_fps_x, h, fps);
  698. }
  699. if ((emu_opt & 0x400) && (PicoMCD & 1))
  700. cd_leds();
  701. //gp2x_video_wait_vsync();
  702. gp2x_video_flip();
  703. if (!(PicoOpt&0x10)) {
  704. if (!(Pico.video.reg[1]&8)) {
  705. if (currentConfig.EmuOpt&0x80) {
  706. DrawLineDest = (unsigned short *) gp2x_screen + 320*8;
  707. } else {
  708. DrawLineDest = (unsigned char *) gp2x_screen + 320*8;
  709. }
  710. } else {
  711. DrawLineDest = gp2x_screen;
  712. }
  713. }
  714. }
  715. // clears whole screen or just the notice area (in all buffers)
  716. static void clearArea(int full)
  717. {
  718. if ((PicoOpt&0x10)||!(currentConfig.EmuOpt&0x80)) {
  719. // 8-bit renderers
  720. if (full) gp2x_memset_all_buffers(0, 0xe0, 320*240);
  721. else gp2x_memset_all_buffers(320*232, 0xe0, 320*8);
  722. } else {
  723. // 16bit accurate renderer
  724. if (full) gp2x_memset_all_buffers(0, 0, 320*240*2);
  725. else gp2x_memset_all_buffers(320*232*2, 0, 320*8*2);
  726. }
  727. }
  728. static void vidResetMode(void)
  729. {
  730. if (PicoOpt&0x10) {
  731. gp2x_video_changemode(8);
  732. } else if (currentConfig.EmuOpt&0x80) {
  733. gp2x_video_changemode(16);
  734. PicoDrawSetColorFormat(1);
  735. PicoScan = EmuScan16;
  736. PicoScan(0, 0);
  737. } else {
  738. gp2x_video_changemode(8);
  739. PicoDrawSetColorFormat(2);
  740. PicoScan = EmuScan8;
  741. PicoScan(0, 0);
  742. }
  743. if ((PicoOpt&0x10)||!(currentConfig.EmuOpt&0x80)) {
  744. // setup pal for 8-bit modes
  745. localPal[0xc0] = 0x0000c000; // MCD LEDs
  746. localPal[0xd0] = 0x00c00000;
  747. localPal[0xe0] = 0x00000000; // reserved pixels for OSD
  748. localPal[0xf0] = 0x00ffffff;
  749. gp2x_video_setpalette(localPal, 0x100);
  750. gp2x_memset_all_buffers(0, 0xe0, 320*240);
  751. gp2x_video_flip();
  752. }
  753. Pico.m.dirtyPal = 1;
  754. // reset scaling
  755. if (currentConfig.scaling == 2 && !(Pico.video.reg[1]&8))
  756. gp2x_video_RGB_setscaling(8, (PicoOpt&0x100)&&!(Pico.video.reg[12]&1) ? 256 : 320, 224);
  757. else gp2x_video_RGB_setscaling(0, (PicoOpt&0x100)&&!(Pico.video.reg[12]&1) ? 256 : 320, 240);
  758. }
  759. static void emu_msg_cb(const char *msg)
  760. {
  761. if ((PicoOpt&0x10)||!(currentConfig.EmuOpt&0x80)) {
  762. // 8-bit renderers
  763. gp2x_memset_all_buffers(320*232, 0xe0, 320*8);
  764. osd_text(4, 232, msg);
  765. gp2x_memcpy_all_buffers((char *)gp2x_screen+320*232, 320*232, 320*8);
  766. } else {
  767. // 16bit accurate renderer
  768. gp2x_memset_all_buffers(320*232*2, 0, 320*8*2);
  769. osd_text(4, 232, msg);
  770. gp2x_memcpy_all_buffers((char *)gp2x_screen+320*232*2, 320*232*2, 320*8*2);
  771. }
  772. gettimeofday(&noticeMsgTime, 0);
  773. noticeMsgTime.tv_sec -= 2;
  774. /* assumption: emu_msg_cb gets called only when something slow is about to happen */
  775. reset_timing = 1;
  776. }
  777. static void emu_state_cb(const char *str)
  778. {
  779. clearArea(0);
  780. blit("", str);
  781. }
  782. static void emu_msg_tray_open(void)
  783. {
  784. strcpy(noticeMsg, "CD tray opened");
  785. gettimeofday(&noticeMsgTime, 0);
  786. }
  787. static void RunEvents(unsigned int which)
  788. {
  789. if(which & 0x1800) { // save or load (but not both)
  790. int do_it = 1;
  791. if ( emu_check_save_file(state_slot) &&
  792. (( (which & 0x1000) && (currentConfig.EmuOpt & 0x800)) || // load
  793. (!(which & 0x1000) && (currentConfig.EmuOpt & 0x200))) ) { // save
  794. unsigned long keys;
  795. blit("", (which & 0x1000) ? "LOAD STATE? (Y=yes, X=no)" : "OVERWRITE SAVE? (Y=yes, X=no)");
  796. while( !((keys = gp2x_joystick_read(1)) & (GP2X_X|GP2X_Y)) )
  797. usleep(50*1024);
  798. if (keys & GP2X_X) do_it = 0;
  799. clearArea(0);
  800. }
  801. if (do_it) {
  802. osd_text(4, 232, (which & 0x1000) ? "LOADING GAME" : "SAVING GAME");
  803. PicoStateProgressCB = emu_state_cb;
  804. gp2x_memcpy_all_buffers(gp2x_screen, 0, 320*240*2);
  805. emu_SaveLoadGame((which & 0x1000) >> 12, 0);
  806. PicoStateProgressCB = NULL;
  807. }
  808. reset_timing = 1;
  809. }
  810. if(which & 0x0400) { // switch renderer
  811. if ( PicoOpt&0x10) { PicoOpt&=~0x10; currentConfig.EmuOpt |= 0x80; }
  812. else if (!(currentConfig.EmuOpt&0x80)) PicoOpt|= 0x10;
  813. else currentConfig.EmuOpt &= ~0x80;
  814. vidResetMode();
  815. if (PicoOpt&0x10) {
  816. strcpy(noticeMsg, " 8bit fast renderer");
  817. } else if (currentConfig.EmuOpt&0x80) {
  818. strcpy(noticeMsg, "16bit accurate renderer");
  819. } else {
  820. strcpy(noticeMsg, " 8bit accurate renderer");
  821. }
  822. gettimeofday(&noticeMsgTime, 0);
  823. }
  824. if(which & 0x0300) {
  825. if(which&0x0200) {
  826. state_slot -= 1;
  827. if(state_slot < 0) state_slot = 9;
  828. } else {
  829. state_slot += 1;
  830. if(state_slot > 9) state_slot = 0;
  831. }
  832. sprintf(noticeMsg, "SAVE SLOT %i [%s]", state_slot, emu_check_save_file(state_slot) ? "USED" : "FREE");
  833. gettimeofday(&noticeMsgTime, 0);
  834. }
  835. if(which & 0x0080) {
  836. engineState = PGS_Menu;
  837. }
  838. }
  839. static void updateMovie(void)
  840. {
  841. int offs = Pico.m.frame_count*3 + 0x40;
  842. if (offs+3 > movie_size) {
  843. free(movie_data);
  844. movie_data = 0;
  845. strcpy(noticeMsg, "END OF MOVIE.");
  846. printf("END OF MOVIE.\n");
  847. gettimeofday(&noticeMsgTime, 0);
  848. } else {
  849. // MXYZ SACB RLDU
  850. PicoPad[0] = ~movie_data[offs] & 0x8f; // ! SCBA RLDU
  851. if(!(movie_data[offs] & 0x10)) PicoPad[0] |= 0x40; // A
  852. if(!(movie_data[offs] & 0x20)) PicoPad[0] |= 0x10; // B
  853. if(!(movie_data[offs] & 0x40)) PicoPad[0] |= 0x20; // A
  854. PicoPad[1] = ~movie_data[offs+1] & 0x8f; // ! SCBA RLDU
  855. if(!(movie_data[offs+1] & 0x10)) PicoPad[1] |= 0x40; // A
  856. if(!(movie_data[offs+1] & 0x20)) PicoPad[1] |= 0x10; // B
  857. if(!(movie_data[offs+1] & 0x40)) PicoPad[1] |= 0x20; // A
  858. PicoPad[0] |= (~movie_data[offs+2] & 0x0A) << 8; // ! MZYX
  859. if(!(movie_data[offs+2] & 0x01)) PicoPad[0] |= 0x0400; // X
  860. if(!(movie_data[offs+2] & 0x04)) PicoPad[0] |= 0x0100; // Z
  861. PicoPad[1] |= (~movie_data[offs+2] & 0xA0) << 4; // ! MZYX
  862. if(!(movie_data[offs+2] & 0x10)) PicoPad[1] |= 0x0400; // X
  863. if(!(movie_data[offs+2] & 0x40)) PicoPad[1] |= 0x0100; // Z
  864. }
  865. }
  866. static void updateKeys(void)
  867. {
  868. unsigned long keys, allActions[2] = { 0, 0 }, events;
  869. static unsigned long prevEvents = 0;
  870. int joy, i;
  871. keys = gp2x_joystick_read(0);
  872. if (keys & GP2X_SELECT) {
  873. engineState = select_exits ? PGS_Quit : PGS_Menu;
  874. // wait until select is released, so menu would not resume game
  875. while (gp2x_joystick_read(1) & GP2X_SELECT) usleep(50*1000);
  876. }
  877. keys &= CONFIGURABLE_KEYS;
  878. for (i = 0; i < 32; i++)
  879. {
  880. if (keys & (1 << i)) {
  881. int pl, acts = currentConfig.KeyBinds[i];
  882. if (!acts) continue;
  883. pl = (acts >> 16) & 1;
  884. if (combo_keys & (1 << i)) {
  885. int u = i+1, acts_c = acts & combo_acts;
  886. // let's try to find the other one
  887. if (acts_c)
  888. for (; u < 32; u++)
  889. if ( (currentConfig.KeyBinds[u] & acts_c) && (keys & (1 << u)) ) {
  890. allActions[pl] |= acts_c;
  891. keys &= ~((1 << i) | (1 << u));
  892. break;
  893. }
  894. // add non-combo actions if combo ones were not found
  895. if (!acts_c || u == 32)
  896. allActions[pl] |= acts & ~combo_acts;
  897. } else {
  898. allActions[pl] |= acts;
  899. }
  900. }
  901. }
  902. // add joy inputs
  903. if (num_of_joys > 0)
  904. {
  905. gp2x_usbjoy_update();
  906. for (joy = 0; joy < num_of_joys; joy++) {
  907. int keys = gp2x_usbjoy_check2(joy);
  908. for (i = 0; i < 32; i++) {
  909. if (keys & (1 << i)) {
  910. int acts = currentConfig.JoyBinds[joy][i];
  911. int pl = (acts >> 16) & 1;
  912. allActions[pl] |= acts;
  913. }
  914. }
  915. }
  916. }
  917. PicoPad[0] = (unsigned short) allActions[0];
  918. PicoPad[1] = (unsigned short) allActions[1];
  919. events = (allActions[0] | allActions[1]) >> 16;
  920. // volume is treated in special way and triggered every frame
  921. if(events & 0x6000) {
  922. int vol = currentConfig.volume;
  923. if (events & 0x2000) {
  924. if (vol < 99) vol++;
  925. } else {
  926. if (vol > 0) vol--;
  927. }
  928. gp2x_sound_volume(vol, vol);
  929. sprintf(noticeMsg, "VOL: %02i", vol);
  930. gettimeofday(&noticeMsgTime, 0);
  931. currentConfig.volume = vol;
  932. }
  933. events &= ~prevEvents;
  934. if (events) RunEvents(events);
  935. if (movie_data) updateMovie();
  936. prevEvents = (allActions[0] | allActions[1]) >> 16;
  937. }
  938. static void updateSound(int len)
  939. {
  940. if (PicoOpt&8) len<<=1;
  941. /* avoid writing audio when lagging behind to prevent audio lag */
  942. if (PicoSkipFrame != 2)
  943. gp2x_sound_write(PsndOut, len<<1);
  944. }
  945. static void SkipFrame(int do_audio)
  946. {
  947. PicoSkipFrame=do_audio ? 1 : 2;
  948. PicoFrame();
  949. PicoSkipFrame=0;
  950. }
  951. void emu_forced_frame(void)
  952. {
  953. int po_old = PicoOpt;
  954. int eo_old = currentConfig.EmuOpt;
  955. PicoOpt &= ~0x0010;
  956. PicoOpt |= 0x4080; // soft_scale | acc_sprites
  957. currentConfig.EmuOpt |= 0x80;
  958. //vidResetMode();
  959. PicoDrawSetColorFormat(1);
  960. PicoScan = EmuScan16;
  961. PicoScan(0, 0);
  962. Pico.m.dirtyPal = 1;
  963. PicoFrameDrawOnly();
  964. /*
  965. if (!(Pico.video.reg[12]&1)) {
  966. vidCpyM2 = vidCpyM2_32col;
  967. clearArea(1);
  968. } else vidCpyM2 = vidCpyM2_40col;
  969. vidCpyM2((unsigned char *)gp2x_screen+320*8, framebuff+328*8);
  970. vidConvCpyRGB32(localPal, Pico.cram, 0x40);
  971. gp2x_video_setpalette(localPal, 0x40);
  972. */
  973. PicoOpt = po_old;
  974. currentConfig.EmuOpt = eo_old;
  975. }
  976. static void simpleWait(int thissec, int lim_time)
  977. {
  978. struct timeval tval;
  979. spend_cycles(1024);
  980. gettimeofday(&tval, 0);
  981. if(thissec != tval.tv_sec) tval.tv_usec+=1000000;
  982. while(tval.tv_usec < lim_time)
  983. {
  984. spend_cycles(1024);
  985. gettimeofday(&tval, 0);
  986. if(thissec != tval.tv_sec) tval.tv_usec+=1000000;
  987. }
  988. }
  989. void emu_Loop(void)
  990. {
  991. static int gp2x_old_clock = 200;
  992. static int PsndRate_old = 0, PicoOpt_old = 0, EmuOpt_old = 0, PsndLen_real = 0, pal_old = 0;
  993. char fpsbuff[24]; // fps count c string
  994. struct timeval tval; // timing
  995. int thissec = 0, frames_done = 0, frames_shown = 0, oldmodes = 0;
  996. int target_fps, target_frametime, lim_time, vsync_offset, i;
  997. char *notice = 0;
  998. printf("entered emu_Loop()\n");
  999. if (gp2x_old_clock != currentConfig.CPUclock) {
  1000. printf("changing clock to %i...", currentConfig.CPUclock); fflush(stdout);
  1001. set_FCLK(currentConfig.CPUclock);
  1002. gp2x_old_clock = currentConfig.CPUclock;
  1003. printf(" done\n");
  1004. }
  1005. if (gp2x_old_gamma != currentConfig.gamma || (EmuOpt_old&0x1000) != (currentConfig.EmuOpt&0x1000)) {
  1006. set_gamma(currentConfig.gamma, !!(currentConfig.EmuOpt&0x1000));
  1007. gp2x_old_gamma = currentConfig.gamma;
  1008. printf("updated gamma to %i, A_SN's curve: %i\n", currentConfig.gamma, !!(currentConfig.EmuOpt&0x1000));
  1009. }
  1010. if ((EmuOpt_old&0x2000) != (currentConfig.EmuOpt&0x2000)) {
  1011. if (currentConfig.EmuOpt&0x2000)
  1012. set_LCD_custom_rate(Pico.m.pal ? LCDR_100 : LCDR_120);
  1013. else unset_LCD_custom_rate();
  1014. }
  1015. EmuOpt_old = currentConfig.EmuOpt;
  1016. fpsbuff[0] = 0;
  1017. // make sure we are in correct mode
  1018. vidResetMode();
  1019. Pico.m.dirtyPal = 1;
  1020. oldmodes = ((Pico.video.reg[12]&1)<<2) ^ 0xc;
  1021. find_combos();
  1022. // pal/ntsc might have changed, reset related stuff
  1023. target_fps = Pico.m.pal ? 50 : 60;
  1024. target_frametime = 1000000/target_fps;
  1025. reset_timing = 1;
  1026. // prepare sound stuff
  1027. if(currentConfig.EmuOpt & 4) {
  1028. int snd_excess_add;
  1029. if(PsndRate != PsndRate_old || (PicoOpt&0x20b) != (PicoOpt_old&0x20b) || Pico.m.pal != pal_old || crashed_940) {
  1030. /* if 940 is turned off, we need it to be put back to sleep */
  1031. if (!(PicoOpt&0x200) && ((PicoOpt^PicoOpt_old)&0x200)) {
  1032. Reset940(1, 2);
  1033. Pause940(1);
  1034. }
  1035. sound_rerate(1);
  1036. }
  1037. //excess_samples = PsndRate - PsndLen*target_fps;
  1038. snd_excess_add = ((PsndRate - PsndLen*target_fps)<<16) / target_fps;
  1039. printf("starting audio: %i len: %i (ex: %04x) stereo: %i, pal: %i\n", PsndRate, PsndLen, snd_excess_add, (PicoOpt&8)>>3, Pico.m.pal);
  1040. gp2x_start_sound(PsndRate, 16, (PicoOpt&8)>>3);
  1041. gp2x_sound_volume(currentConfig.volume, currentConfig.volume);
  1042. PicoWriteSound = updateSound;
  1043. memset(sndBuffer, 0, sizeof(sndBuffer));
  1044. PsndOut = sndBuffer;
  1045. PsndRate_old = PsndRate;
  1046. PsndLen_real = PsndLen;
  1047. PicoOpt_old = PicoOpt;
  1048. pal_old = Pico.m.pal;
  1049. } else {
  1050. PsndOut = 0;
  1051. }
  1052. // prepare CD buffer
  1053. if (PicoMCD & 1) PicoCDBufferInit();
  1054. // calc vsync offset to sync timing code with vsync
  1055. if (currentConfig.EmuOpt&0x2000) {
  1056. gettimeofday(&tval, 0);
  1057. gp2x_video_wait_vsync();
  1058. gettimeofday(&tval, 0);
  1059. vsync_offset = tval.tv_usec;
  1060. while (vsync_offset >= target_frametime)
  1061. vsync_offset -= target_frametime;
  1062. if (!vsync_offset) vsync_offset++;
  1063. printf("vsync_offset: %i\n", vsync_offset);
  1064. } else
  1065. vsync_offset = 0;
  1066. // loop?
  1067. while (engineState == PGS_Running)
  1068. {
  1069. int modes;
  1070. gettimeofday(&tval, 0);
  1071. if(reset_timing) {
  1072. reset_timing = 0;
  1073. thissec = tval.tv_sec;
  1074. frames_shown = frames_done = tval.tv_usec/target_frametime;
  1075. }
  1076. // show notice message?
  1077. if(noticeMsgTime.tv_sec) {
  1078. static int noticeMsgSum;
  1079. if((tval.tv_sec*1000000+tval.tv_usec) - (noticeMsgTime.tv_sec*1000000+noticeMsgTime.tv_usec) > 2000000) { // > 2.0 sec
  1080. noticeMsgTime.tv_sec = noticeMsgTime.tv_usec = 0;
  1081. clearArea(0);
  1082. notice = 0;
  1083. } else {
  1084. int sum = noticeMsg[0]+noticeMsg[1]+noticeMsg[2];
  1085. if (sum != noticeMsgSum) { clearArea(0); noticeMsgSum = sum; }
  1086. notice = noticeMsg;
  1087. }
  1088. }
  1089. // check for mode changes
  1090. modes = ((Pico.video.reg[12]&1)<<2)|(Pico.video.reg[1]&8);
  1091. if (modes != oldmodes) {
  1092. int scalex = 320;
  1093. osd_fps_x = OSD_FPS_X;
  1094. if (modes & 4) {
  1095. vidCpyM2 = vidCpyM2_40col;
  1096. } else {
  1097. if (PicoOpt & 0x100) {
  1098. vidCpyM2 = vidCpyM2_32col_nobord;
  1099. scalex = 256;
  1100. osd_fps_x = OSD_FPS_X - 64;
  1101. } else {
  1102. vidCpyM2 = vidCpyM2_32col;
  1103. }
  1104. }
  1105. if (currentConfig.scaling == 2 && !(modes&8)) // want vertical scaling and game is not in 240 line mode
  1106. gp2x_video_RGB_setscaling(8, scalex, 224);
  1107. else gp2x_video_RGB_setscaling(0, scalex, 240);
  1108. oldmodes = modes;
  1109. clearArea(1);
  1110. }
  1111. // second changed?
  1112. if(thissec != tval.tv_sec) {
  1113. #ifdef BENCHMARK
  1114. static int bench = 0, bench_fps = 0, bench_fps_s = 0, bfp = 0, bf[4];
  1115. if(++bench == 10) {
  1116. bench = 0;
  1117. bench_fps_s = bench_fps;
  1118. bf[bfp++ & 3] = bench_fps;
  1119. bench_fps = 0;
  1120. }
  1121. bench_fps += frames_shown;
  1122. sprintf(fpsbuff, "%02i/%02i/%02i", frames_shown, bench_fps_s, (bf[0]+bf[1]+bf[2]+bf[3])>>2);
  1123. #else
  1124. if(currentConfig.EmuOpt & 2)
  1125. sprintf(fpsbuff, "%02i/%02i", frames_shown, frames_done);
  1126. #endif
  1127. thissec = tval.tv_sec;
  1128. if(PsndOut == 0 && currentConfig.Frameskip >= 0) {
  1129. frames_done = frames_shown = 0;
  1130. } else {
  1131. // it is quite common for this implementation to leave 1 fame unfinished
  1132. // when second changes, but we don't want buffer to starve.
  1133. if(PsndOut && frames_done < target_fps && frames_done > target_fps-5) {
  1134. updateKeys();
  1135. SkipFrame(1); frames_done++;
  1136. }
  1137. frames_done -= target_fps; if (frames_done < 0) frames_done = 0;
  1138. frames_shown -= target_fps; if (frames_shown < 0) frames_shown = 0;
  1139. if (frames_shown > frames_done) frames_shown = frames_done;
  1140. }
  1141. }
  1142. lim_time = (frames_done+1) * target_frametime + vsync_offset;
  1143. if(currentConfig.Frameskip >= 0) { // frameskip enabled
  1144. for(i = 0; i < currentConfig.Frameskip; i++) {
  1145. updateKeys();
  1146. SkipFrame(1); frames_done++;
  1147. if (PsndOut) { // do framelimitting if sound is enabled
  1148. gettimeofday(&tval, 0);
  1149. if(thissec != tval.tv_sec) tval.tv_usec+=1000000;
  1150. if(tval.tv_usec < lim_time) { // we are too fast
  1151. simpleWait(thissec, lim_time);
  1152. }
  1153. }
  1154. lim_time += target_frametime;
  1155. }
  1156. } else if(tval.tv_usec > lim_time) { // auto frameskip
  1157. // no time left for this frame - skip
  1158. if (tval.tv_usec - lim_time >= 0x300000) {
  1159. /* something caused a slowdown for us (disk access? cache flush?)
  1160. * try to recover by resetting timing... */
  1161. reset_timing = 1;
  1162. continue;
  1163. }
  1164. updateKeys();
  1165. SkipFrame(tval.tv_usec < lim_time+target_frametime*2); frames_done++;
  1166. continue;
  1167. }
  1168. updateKeys();
  1169. PicoFrame();
  1170. #if 0
  1171. if (Pico.m.frame_count == 31563) {
  1172. FILE *f;
  1173. f = fopen("ram_p.bin", "wb");
  1174. if (!f) { printf("!f\n"); exit(1); }
  1175. fwrite(Pico.ram, 1, 0x10000, f);
  1176. fclose(f);
  1177. exit(0);
  1178. }
  1179. #endif
  1180. #if 0
  1181. // debug
  1182. {
  1183. #define BYTE unsigned char
  1184. #define WORD unsigned short
  1185. struct
  1186. {
  1187. BYTE IDLength; /* 00h Size of Image ID field */
  1188. BYTE ColorMapType; /* 01h Color map type */
  1189. BYTE ImageType; /* 02h Image type code */
  1190. WORD CMapStart; /* 03h Color map origin */
  1191. WORD CMapLength; /* 05h Color map length */
  1192. BYTE CMapDepth; /* 07h Depth of color map entries */
  1193. WORD XOffset; /* 08h X origin of image */
  1194. WORD YOffset; /* 0Ah Y origin of image */
  1195. WORD Width; /* 0Ch Width of image */
  1196. WORD Height; /* 0Eh Height of image */
  1197. BYTE PixelDepth; /* 10h Image pixel size */
  1198. BYTE ImageDescriptor; /* 11h Image descriptor byte */
  1199. } __attribute__((packed)) TGAHEAD;
  1200. static unsigned short oldscr[320*240];
  1201. FILE *f; char name[128]; int i;
  1202. memset(&TGAHEAD, 0, sizeof(TGAHEAD));
  1203. TGAHEAD.ImageType = 2;
  1204. TGAHEAD.Width = 320;
  1205. TGAHEAD.Height = 240;
  1206. TGAHEAD.PixelDepth = 16;
  1207. TGAHEAD.ImageDescriptor = 2<<4; // image starts at top-left
  1208. #define CONV(X) (((X>>1)&0x7fe0)|(X&0x1f)) // 555?
  1209. for (i = 0; i < 320*240; i++)
  1210. if(oldscr[i] != CONV(((unsigned short *)gp2x_screen)[i])) break;
  1211. if (i < 320*240)
  1212. {
  1213. for (i = 0; i < 320*240; i++)
  1214. oldscr[i] = CONV(((unsigned short *)gp2x_screen)[i]);
  1215. sprintf(name, "%05i.tga", Pico.m.frame_count);
  1216. f = fopen(name, "wb");
  1217. if (!f) { printf("!f\n"); exit(1); }
  1218. fwrite(&TGAHEAD, 1, sizeof(TGAHEAD), f);
  1219. fwrite(oldscr, 1, 320*240*2, f);
  1220. fclose(f);
  1221. }
  1222. }
  1223. #endif
  1224. // check time
  1225. gettimeofday(&tval, 0);
  1226. if (thissec != tval.tv_sec) tval.tv_usec+=1000000;
  1227. if (currentConfig.Frameskip < 0 && tval.tv_usec - lim_time >= 0x300000) // slowdown detection
  1228. reset_timing = 1;
  1229. else if (PsndOut != NULL || currentConfig.Frameskip < 0)
  1230. {
  1231. // sleep or vsync if we are still too fast
  1232. // usleep sleeps for ~20ms minimum, so it is not a solution here
  1233. if(tval.tv_usec < lim_time)
  1234. {
  1235. // we are too fast
  1236. if (vsync_offset) {
  1237. if (lim_time - tval.tv_usec > target_frametime/2)
  1238. simpleWait(thissec, lim_time - target_frametime/4);
  1239. gp2x_video_wait_vsync();
  1240. } else {
  1241. simpleWait(thissec, lim_time);
  1242. }
  1243. }
  1244. }
  1245. blit(fpsbuff, notice);
  1246. frames_done++; frames_shown++;
  1247. }
  1248. if (PicoMCD & 1) PicoCDBufferFree();
  1249. // save SRAM
  1250. if((currentConfig.EmuOpt & 1) && SRam.changed) {
  1251. emu_state_cb("Writing SRAM/BRAM..");
  1252. emu_SaveLoadGame(0, 1);
  1253. SRam.changed = 0;
  1254. }
  1255. // if in 8bit mode, generate 16bit image for menu background
  1256. if ((PicoOpt&0x10) || !(currentConfig.EmuOpt&0x80))
  1257. emu_forced_frame();
  1258. }
  1259. void emu_ResetGame(void)
  1260. {
  1261. PicoReset(0);
  1262. reset_timing = 1;
  1263. }
  1264. size_t gzRead2(void *p, size_t _size, size_t _n, void *file)
  1265. {
  1266. return gzread(file, p, _n);
  1267. }
  1268. size_t gzWrite2(void *p, size_t _size, size_t _n, void *file)
  1269. {
  1270. return gzwrite(file, p, _n);
  1271. }
  1272. static int try_ropen_file(const char *fname)
  1273. {
  1274. FILE *f;
  1275. f = fopen(fname, "rb");
  1276. if (f) {
  1277. fclose(f);
  1278. return 1;
  1279. }
  1280. return 0;
  1281. }
  1282. char *emu_GetSaveFName(int load, int is_sram, int slot)
  1283. {
  1284. static char saveFname[512];
  1285. char ext[16];
  1286. if (is_sram)
  1287. {
  1288. romfname_ext(saveFname, (PicoMCD&1) ? "brm/" : "srm/", (PicoMCD&1) ? ".brm" : ".srm");
  1289. if (load) {
  1290. if (try_ropen_file(saveFname)) return saveFname;
  1291. // try in current dir..
  1292. romfname_ext(saveFname, NULL, (PicoMCD&1) ? ".brm" : ".srm");
  1293. if (try_ropen_file(saveFname)) return saveFname;
  1294. return NULL; // give up
  1295. }
  1296. }
  1297. else
  1298. {
  1299. ext[0] = 0;
  1300. if(slot > 0 && slot < 10) sprintf(ext, ".%i", slot);
  1301. strcat(ext, (currentConfig.EmuOpt & 8) ? ".mds.gz" : ".mds");
  1302. romfname_ext(saveFname, "mds/", ext);
  1303. if (load) {
  1304. if (try_ropen_file(saveFname)) return saveFname;
  1305. romfname_ext(saveFname, NULL, ext);
  1306. if (try_ropen_file(saveFname)) return saveFname;
  1307. if (currentConfig.EmuOpt & 8) {
  1308. ext[0] = 0;
  1309. if(slot > 0 && slot < 10) sprintf(ext, ".%i", slot);
  1310. strcat(ext, ".mds");
  1311. romfname_ext(saveFname, "mds/", ext);
  1312. if (try_ropen_file(saveFname)) return saveFname;
  1313. romfname_ext(saveFname, NULL, ext);
  1314. if (try_ropen_file(saveFname)) return saveFname;
  1315. }
  1316. return NULL;
  1317. }
  1318. }
  1319. return saveFname;
  1320. }
  1321. int emu_check_save_file(int slot)
  1322. {
  1323. return emu_GetSaveFName(1, 0, slot) ? 1 : 0;
  1324. }
  1325. void emu_set_save_cbs(int gz)
  1326. {
  1327. if (gz) {
  1328. areaRead = gzRead2;
  1329. areaWrite = gzWrite2;
  1330. areaEof = (areaeof *) gzeof;
  1331. areaSeek = (areaseek *) gzseek;
  1332. areaClose = (areaclose *) gzclose;
  1333. } else {
  1334. areaRead = (arearw *) fread;
  1335. areaWrite = (arearw *) fwrite;
  1336. areaEof = (areaeof *) feof;
  1337. areaSeek = (areaseek *) fseek;
  1338. areaClose = (areaclose *) fclose;
  1339. }
  1340. }
  1341. int emu_SaveLoadGame(int load, int sram)
  1342. {
  1343. int ret = 0;
  1344. char *saveFname;
  1345. // make save filename
  1346. saveFname = emu_GetSaveFName(load, sram, state_slot);
  1347. if (saveFname == NULL) {
  1348. if (!sram) {
  1349. strcpy(noticeMsg, load ? "LOAD FAILED (missing file)" : "SAVE FAILED ");
  1350. gettimeofday(&noticeMsgTime, 0);
  1351. }
  1352. return -1;
  1353. }
  1354. printf("saveLoad (%i, %i): %s\n", load, sram, saveFname);
  1355. if(sram) {
  1356. FILE *sramFile;
  1357. int sram_size;
  1358. unsigned char *sram_data;
  1359. int truncate = 1;
  1360. if (PicoMCD&1) {
  1361. if (PicoOpt&0x8000) { // MCD RAM cart?
  1362. sram_size = 0x12000;
  1363. sram_data = SRam.data;
  1364. if (sram_data)
  1365. memcpy32((int *)sram_data, (int *)Pico_mcd->bram, 0x2000/4);
  1366. } else {
  1367. sram_size = 0x2000;
  1368. sram_data = Pico_mcd->bram;
  1369. truncate = 0; // the .brm may contain RAM cart data after normal brm
  1370. }
  1371. } else {
  1372. sram_size = SRam.end-SRam.start+1;
  1373. if(SRam.reg_back & 4) sram_size=0x2000;
  1374. sram_data = SRam.data;
  1375. }
  1376. if (!sram_data) return 0; // SRam forcefully disabled for this game
  1377. if (load) {
  1378. sramFile = fopen(saveFname, "rb");
  1379. if(!sramFile) return -1;
  1380. fread(sram_data, 1, sram_size, sramFile);
  1381. fclose(sramFile);
  1382. if ((PicoMCD&1) && (PicoOpt&0x8000))
  1383. memcpy32((int *)Pico_mcd->bram, (int *)sram_data, 0x2000/4);
  1384. } else {
  1385. // sram save needs some special processing
  1386. // see if we have anything to save
  1387. for (; sram_size > 0; sram_size--)
  1388. if (sram_data[sram_size-1]) break;
  1389. if (sram_size) {
  1390. sramFile = fopen(saveFname, truncate ? "wb" : "r+b");
  1391. if (!sramFile) sramFile = fopen(saveFname, "wb"); // retry
  1392. if (!sramFile) return -1;
  1393. ret = fwrite(sram_data, 1, sram_size, sramFile);
  1394. ret = (ret != sram_size) ? -1 : 0;
  1395. fclose(sramFile);
  1396. #ifndef NO_SYNC
  1397. sync();
  1398. #endif
  1399. }
  1400. }
  1401. return ret;
  1402. }
  1403. else
  1404. {
  1405. void *PmovFile = NULL;
  1406. if (strcmp(saveFname + strlen(saveFname) - 3, ".gz") == 0) {
  1407. if( (PmovFile = gzopen(saveFname, load ? "rb" : "wb")) ) {
  1408. emu_set_save_cbs(1);
  1409. if(!load) gzsetparams(PmovFile, 9, Z_DEFAULT_STRATEGY);
  1410. }
  1411. }
  1412. else
  1413. {
  1414. if( (PmovFile = fopen(saveFname, load ? "rb" : "wb")) ) {
  1415. emu_set_save_cbs(0);
  1416. }
  1417. }
  1418. if(PmovFile) {
  1419. ret = PmovState(load ? 6 : 5, PmovFile);
  1420. areaClose(PmovFile);
  1421. PmovFile = 0;
  1422. if (load) Pico.m.dirtyPal=1;
  1423. #ifndef NO_SYNC
  1424. else sync();
  1425. #endif
  1426. }
  1427. else ret = -1;
  1428. if (!ret)
  1429. strcpy(noticeMsg, load ? "GAME LOADED " : "GAME SAVED ");
  1430. else
  1431. {
  1432. strcpy(noticeMsg, load ? "LOAD FAILED " : "SAVE FAILED ");
  1433. ret = -1;
  1434. }
  1435. gettimeofday(&noticeMsgTime, 0);
  1436. return ret;
  1437. }
  1438. }