emu.c 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923
  1. /*
  2. * PicoDrive
  3. * (C) notaz, 2007-2010
  4. *
  5. * This work is licensed under the terms of MAME license.
  6. * See COPYING file in the top-level directory.
  7. */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <stdarg.h>
  12. #ifdef __GP2X__
  13. #include <unistd.h>
  14. #endif
  15. #include "../libpicofe/posix.h"
  16. #include "../libpicofe/input.h"
  17. #include "../libpicofe/fonts.h"
  18. #include "../libpicofe/sndout.h"
  19. #include "../libpicofe/lprintf.h"
  20. #include "../libpicofe/plat.h"
  21. #include "emu.h"
  22. #include "configfile_fk.h"
  23. #include "input_pico.h"
  24. #include "menu_pico.h"
  25. #include "config_file.h"
  26. #include <pico/pico_int.h>
  27. #include <pico/patch.h>
  28. #ifdef USE_LIBRETRO_VFS
  29. #include "file_stream_transforms.h"
  30. #endif
  31. #if defined(__GNUC__) && __GNUC__ >= 7
  32. #pragma GCC diagnostic ignored "-Wformat-truncation"
  33. #endif
  34. #ifndef _WIN32
  35. #define PATH_SEP "/"
  36. #define PATH_SEP_C '/'
  37. #else
  38. #define PATH_SEP "\\"
  39. #define PATH_SEP_C '\\'
  40. #endif
  41. #define STATUS_MSG_TIMEOUT 2000
  42. void *g_screen_ptr;
  43. int g_screen_width = 320;
  44. int g_screen_height = 240;
  45. int g_screen_ppitch = 320; // pitch in pixels
  46. const char *PicoConfigFile = "config2.cfg";
  47. currentConfig_t currentConfig, defaultConfig;
  48. int state_slot = 0;
  49. int config_slot = 0, config_slot_current = 0;
  50. int pico_pen_x = 320/2, pico_pen_y = 240/2;
  51. int pico_inp_mode;
  52. int flip_after_sync;
  53. int engineState = PGS_Menu;
  54. int show_fps_bypass = 0;
  55. int need_screen_cleared = 0;
  56. static short __attribute__((aligned(4))) sndBuffer[2*44100/50];
  57. /* tmp buff to reduce stack usage for plats with small stack */
  58. static char static_buff[1024];
  59. const char *rom_fname_reload;
  60. char rom_fname_loaded[1024];
  61. int reset_timing = 0;
  62. static unsigned int notice_msg_time; /* when started showing */
  63. static char noticeMsg[40];
  64. unsigned char *movie_data = NULL;
  65. static int movie_size = 0;
  66. /* don't use tolower() for easy old glibc binary compatibility */
  67. static void strlwr_(char *string)
  68. {
  69. char *p;
  70. for (p = string; *p; p++)
  71. if ('A' <= *p && *p <= 'Z')
  72. *p += 'a' - 'A';
  73. }
  74. static int try_rfn_cut(char *fname)
  75. {
  76. FILE *tmp;
  77. char *p;
  78. p = fname + strlen(fname) - 1;
  79. for (; p > fname; p--)
  80. if (*p == '.') break;
  81. *p = 0;
  82. if((tmp = fopen(fname, "rb"))) {
  83. fclose(tmp);
  84. return 1;
  85. }
  86. return 0;
  87. }
  88. static void get_ext(const char *file, char *ext)
  89. {
  90. const char *p;
  91. p = file + strlen(file) - 4;
  92. if (p < file) p = file;
  93. strncpy(ext, p, 4);
  94. ext[4] = 0;
  95. strlwr_(ext);
  96. }
  97. static void fname_ext(char *dst, int dstlen, const char *prefix, const char *ext, const char *fname)
  98. {
  99. int prefix_len = 0;
  100. const char *p;
  101. *dst = 0;
  102. if (prefix) {
  103. /*int len = plat_get_root_dir(dst, dstlen);
  104. strcpy(dst + len, prefix);
  105. prefix_len = len + strlen(prefix);*/
  106. /* Saves are in ROM folder */
  107. prefix_len = strlen(mRomPath)+1;
  108. sprintf(dst, "%s/", mRomPath);
  109. }
  110. p = fname + strlen(fname) - 1;
  111. for (; p >= fname && *p != PATH_SEP_C; p--)
  112. ;
  113. p++;
  114. strncpy(dst + prefix_len, p, dstlen - prefix_len - 1);
  115. dst[dstlen - 8] = 0;
  116. if ((p = strrchr(dst, '.')) != NULL)
  117. dst[p-dst] = 0;
  118. if (ext)
  119. strcat(dst, ext);
  120. }
  121. static void romfname_ext(char *dst, int dstlen, const char *prefix, const char *ext)
  122. {
  123. fname_ext(dst, dstlen, prefix, ext, rom_fname_loaded);
  124. }
  125. void emu_status_msg(const char *format, ...)
  126. {
  127. va_list vl;
  128. int ret;
  129. va_start(vl, format);
  130. ret = vsnprintf(noticeMsg, sizeof(noticeMsg), format, vl);
  131. va_end(vl);
  132. /* be sure old text gets overwritten */
  133. for (; ret < 28; ret++)
  134. noticeMsg[ret] = ' ';
  135. noticeMsg[ret] = 0;
  136. notice_msg_time = plat_get_ticks_ms();
  137. }
  138. static const char * const biosfiles_us[] = {
  139. "us_scd2_9306", "SegaCDBIOS9303", "us_scd1_9210", "bios_CD_U"
  140. };
  141. static const char * const biosfiles_eu[] = {
  142. "eu_mcd2_9306", "eu_mcd2_9303", "eu_mcd1_9210", "bios_CD_E"
  143. };
  144. static const char * const biosfiles_jp[] = {
  145. "jp_mcd2_921222", "jp_mcd1_9112", "jp_mcd1_9111", "bios_CD_J"
  146. };
  147. static const char *find_bios(int *region, const char *cd_fname)
  148. {
  149. int i, count;
  150. const char * const *files;
  151. FILE *f = NULL;
  152. int ret;
  153. // we need to have config loaded at this point
  154. ret = emu_read_config(cd_fname, 0);
  155. if (!ret) emu_read_config(NULL, 0);
  156. if (PicoIn.regionOverride) {
  157. *region = PicoIn.regionOverride;
  158. lprintf("override region to %s\n", *region != 4 ?
  159. (*region == 8 ? "EU" : "JAP") : "USA");
  160. }
  161. if (*region == 4) { // US
  162. files = biosfiles_us;
  163. count = sizeof(biosfiles_us) / sizeof(char *);
  164. } else if (*region == 8) { // EU
  165. files = biosfiles_eu;
  166. count = sizeof(biosfiles_eu) / sizeof(char *);
  167. } else if (*region == 1 || *region == 2) {
  168. files = biosfiles_jp;
  169. count = sizeof(biosfiles_jp) / sizeof(char *);
  170. } else {
  171. return 0;
  172. }
  173. /** Check Bios files in home directory */
  174. for (i = 0; i < count; i++)
  175. {
  176. emu_make_path(static_buff, files[i], sizeof(static_buff) - 4);
  177. //printf("bios name static_buff: %s\n", static_buff);
  178. strcat(static_buff, ".bin");
  179. f = fopen(static_buff, "rb");
  180. if (f) break;
  181. static_buff[strlen(static_buff) - 4] = 0;
  182. strcat(static_buff, ".zip");
  183. f = fopen(static_buff, "rb");
  184. if (f) break;
  185. }
  186. /** Check Bios files in <rom path>/bios */
  187. if(!f){
  188. for (i = 0; i < count; i++)
  189. {
  190. sprintf(static_buff, "%s/bios/%s", mRomPath, files[i]);
  191. printf("static_buff: %s\n", static_buff);
  192. strcat(static_buff, ".bin");
  193. f = fopen(static_buff, "rb");
  194. if (f) break;
  195. static_buff[strlen(static_buff) - 4] = 0;
  196. strcat(static_buff, ".zip");
  197. f = fopen(static_buff, "rb");
  198. if (f) break;
  199. }
  200. }
  201. /** Check Bios files in rom path */
  202. if(!f){
  203. for (i = 0; i < count; i++)
  204. {
  205. sprintf(static_buff, "%s/%s", mRomPath, files[i]);
  206. printf("static_buff: %s\n", static_buff);
  207. strcat(static_buff, ".bin");
  208. f = fopen(static_buff, "rb");
  209. if (f) break;
  210. static_buff[strlen(static_buff) - 4] = 0;
  211. strcat(static_buff, ".zip");
  212. f = fopen(static_buff, "rb");
  213. if (f) break;
  214. }
  215. }
  216. if (f) {
  217. lprintf("using bios: %s\n", static_buff);
  218. fclose(f);
  219. return static_buff;
  220. } else {
  221. char* country;
  222. char** bios_names;
  223. if(*region == 4){ //USA
  224. country = "USA";
  225. bios_names = biosfiles_us;
  226. }
  227. else if(*region == 8){ //EU
  228. country = "EU";
  229. bios_names = biosfiles_eu;
  230. }
  231. else{ //JAP
  232. country = "JAP";
  233. bios_names = biosfiles_jp;
  234. }
  235. sprintf(static_buff, "no %s BIOS files found, read docs", country);
  236. menu_update_msg(static_buff);
  237. /** Set notif for BIOS */
  238. char shell_cmd[400];
  239. sprintf(shell_cmd, "%s 0 \" %s BIOS FILE MISSING^^Connect your FunKey S to ^your computer and copy the^BIOS file in the folder:^ Sega Genesis/bios/^^The file can be called:^ - %s.bin^ - %s.bin^ - %s.bin^ - %s.bin^^For more instructions:^www.funkey-project.com^^Press any button to exit...\"",
  240. SHELL_CMD_NOTIF_SET, country, bios_names[0], bios_names[1], bios_names[2], bios_names[3]);
  241. FILE *fp = popen(shell_cmd, "r");
  242. if (fp == NULL) {
  243. printf("In %s, Failed to run command %s\n", __func__, shell_cmd);
  244. } else {
  245. pclose(fp);
  246. }
  247. /** Wait for key press */
  248. SDL_Event event;
  249. while(event.type != SDL_KEYUP && event.type != SDL_QUIT){
  250. while (SDL_PollEvent(&event))
  251. SDL_Delay(60);
  252. }
  253. /** Clear notif for BIOS */
  254. fp = popen(SHELL_CMD_NOTIF_CLEAR, "r");
  255. if (fp == NULL) {
  256. printf("In %s, Failed to run command %s\n", __func__, SHELL_CMD_NOTIF_CLEAR);
  257. } else {
  258. pclose(fp);
  259. }
  260. /** Force clean exit */
  261. //engineState = PGS_Quit;
  262. emu_finish();
  263. plat_finish();
  264. plat_target_finish();
  265. exit(0);
  266. return NULL;
  267. }
  268. }
  269. /* check if the name begins with BIOS name */
  270. /*
  271. static int emu_isBios(const char *name)
  272. {
  273. int i;
  274. for (i = 0; i < sizeof(biosfiles_us)/sizeof(biosfiles_us[0]); i++)
  275. if (strstr(name, biosfiles_us[i]) != NULL) return 1;
  276. for (i = 0; i < sizeof(biosfiles_eu)/sizeof(biosfiles_eu[0]); i++)
  277. if (strstr(name, biosfiles_eu[i]) != NULL) return 1;
  278. for (i = 0; i < sizeof(biosfiles_jp)/sizeof(biosfiles_jp[0]); i++)
  279. if (strstr(name, biosfiles_jp[i]) != NULL) return 1;
  280. return 0;
  281. }
  282. */
  283. static int extract_text(char *dest, const unsigned char *src, int len, int swab)
  284. {
  285. char *p = dest;
  286. int i;
  287. if (swab) swab = 1;
  288. for (i = len - 1; i >= 0; i--)
  289. {
  290. if (src[i^swab] != ' ') break;
  291. }
  292. len = i + 1;
  293. for (i = 0; i < len; i++)
  294. {
  295. unsigned char s = src[i^swab];
  296. if (s >= 0x20 && s < 0x7f && s != '#' && s != '|' &&
  297. s != '[' && s != ']' && s != '\\')
  298. {
  299. *p++ = s;
  300. }
  301. else
  302. {
  303. sprintf(p, "\\%02x", s);
  304. p += 3;
  305. }
  306. }
  307. return p - dest;
  308. }
  309. static char *emu_make_rom_id(const char *fname)
  310. {
  311. static char id_string[3+0xe*3+0x3*3+0x30*3+3];
  312. int pos, swab = 1;
  313. if (PicoIn.AHW & PAHW_MCD) {
  314. strcpy(id_string, "CD|");
  315. swab = 0;
  316. }
  317. else if (PicoIn.AHW & PAHW_SMS)
  318. strcpy(id_string, "MS|");
  319. else strcpy(id_string, "MD|");
  320. pos = 3;
  321. if (!(PicoIn.AHW & PAHW_SMS)) {
  322. pos += extract_text(id_string + pos, media_id_header + 0x80, 0x0e, swab); // serial
  323. id_string[pos] = '|'; pos++;
  324. pos += extract_text(id_string + pos, media_id_header + 0xf0, 0x03, swab); // region
  325. id_string[pos] = '|'; pos++;
  326. pos += extract_text(id_string + pos, media_id_header + 0x50, 0x30, swab); // overseas name
  327. id_string[pos] = 0;
  328. if (pos > 5)
  329. return id_string;
  330. pos = 3;
  331. }
  332. // can't find name in ROM, use filename
  333. fname_ext(id_string + 3, sizeof(id_string) - 3, NULL, NULL, fname);
  334. return id_string;
  335. }
  336. // buffer must be at least 150 byte long
  337. void emu_get_game_name(char *str150)
  338. {
  339. int ret, swab = (PicoIn.AHW & PAHW_MCD) ? 0 : 1;
  340. char *s, *d;
  341. ret = extract_text(str150, media_id_header + 0x50, 0x30, swab); // overseas name
  342. for (s = d = str150 + 1; s < str150+ret; s++)
  343. {
  344. if (*s == 0) break;
  345. if (*s != ' ' || d[-1] != ' ')
  346. *d++ = *s;
  347. }
  348. *d = 0;
  349. }
  350. static void system_announce(void)
  351. {
  352. const char *sys_name, *tv_standard, *extra = "";
  353. int fps;
  354. if (PicoIn.AHW & PAHW_SMS) {
  355. sys_name = "Master System";
  356. #ifdef NO_SMS
  357. extra = " [no support]";
  358. #endif
  359. } else if (PicoIn.AHW & PAHW_PICO) {
  360. sys_name = "Pico";
  361. } else if ((PicoIn.AHW & (PAHW_32X|PAHW_MCD)) == (PAHW_32X|PAHW_MCD)) {
  362. sys_name = "32X + Mega CD";
  363. if ((Pico.m.hardware & 0xc0) == 0x80)
  364. sys_name = "32X + Sega CD";
  365. } else if (PicoIn.AHW & PAHW_MCD) {
  366. sys_name = "Mega CD";
  367. if ((Pico.m.hardware & 0xc0) == 0x80)
  368. sys_name = "Sega CD";
  369. } else if (PicoIn.AHW & PAHW_32X) {
  370. sys_name = "32X";
  371. } else {
  372. sys_name = "MegaDrive";
  373. if ((Pico.m.hardware & 0xc0) == 0x80)
  374. sys_name = "Genesis";
  375. }
  376. tv_standard = Pico.m.pal ? "PAL" : "NTSC";
  377. fps = Pico.m.pal ? 50 : 60;
  378. //emu_status_msg("%s %s / %dFPS%s", tv_standard, sys_name, fps, extra);
  379. printf("\nSystem Announce: %s, %s / %dFPS%s\n", sys_name, tv_standard, fps, extra);
  380. printf("PicoIn.AHW = %d, Pico.m.hardware=%d\n", PicoIn.AHW, Pico.m.hardware);
  381. }
  382. static void do_region_override(const char *media_fname)
  383. {
  384. // we only need to override region if config tells us so
  385. int ret = emu_read_config(media_fname, 0);
  386. if (!ret) emu_read_config(NULL, 0);
  387. }
  388. int emu_reload_rom(const char *rom_fname_in)
  389. {
  390. // use setting before rom config is loaded
  391. int autoload = g_autostateld_opt;
  392. char *rom_fname = NULL;
  393. char ext[5];
  394. enum media_type_e media_type;
  395. int menu_romload_started = 0;
  396. char carthw_path[512];
  397. int retval = 0;
  398. lprintf("emu_ReloadRom(%s)\n", rom_fname_in);
  399. rom_fname = strdup(rom_fname_in);
  400. if (rom_fname == NULL)
  401. return 0;
  402. get_ext(rom_fname, ext);
  403. // early cleanup
  404. PicoPatchUnload();
  405. if (movie_data) {
  406. free(movie_data);
  407. movie_data = 0;
  408. }
  409. if (!strcmp(ext, ".gmv"))
  410. {
  411. // check for both gmv and rom
  412. int dummy;
  413. FILE *movie_file = fopen(rom_fname, "rb");
  414. if (!movie_file) {
  415. menu_update_msg("Failed to open movie.");
  416. goto out;
  417. }
  418. fseek(movie_file, 0, SEEK_END);
  419. movie_size = ftell(movie_file);
  420. fseek(movie_file, 0, SEEK_SET);
  421. if (movie_size < 64+3) {
  422. menu_update_msg("Invalid GMV file.");
  423. fclose(movie_file);
  424. goto out;
  425. }
  426. movie_data = malloc(movie_size);
  427. if (movie_data == NULL) {
  428. menu_update_msg("low memory.");
  429. fclose(movie_file);
  430. goto out;
  431. }
  432. dummy = fread(movie_data, 1, movie_size, movie_file);
  433. fclose(movie_file);
  434. if (strncmp((char *)movie_data, "Gens Movie TEST", 15) != 0) {
  435. menu_update_msg("Invalid GMV file.");
  436. goto out;
  437. }
  438. dummy = try_rfn_cut(rom_fname) || try_rfn_cut(rom_fname);
  439. if (!dummy) {
  440. menu_update_msg("Could't find a ROM for movie.");
  441. goto out;
  442. }
  443. get_ext(rom_fname, ext);
  444. lprintf("gmv loaded for %s\n", rom_fname);
  445. }
  446. else if (!strcmp(ext, ".pat"))
  447. {
  448. int dummy;
  449. PicoPatchLoad(rom_fname);
  450. dummy = try_rfn_cut(rom_fname) || try_rfn_cut(rom_fname);
  451. if (!dummy) {
  452. menu_update_msg("Could't find a ROM to patch.");
  453. goto out;
  454. }
  455. get_ext(rom_fname, ext);
  456. }
  457. menu_romload_prepare(rom_fname); // also CD load
  458. menu_romload_started = 1;
  459. emu_make_path(carthw_path, "carthw.cfg", sizeof(carthw_path));
  460. media_type = PicoLoadMedia(rom_fname, carthw_path,
  461. find_bios, do_region_override);
  462. switch (media_type) {
  463. case PM_BAD_DETECT:
  464. menu_update_msg("Not a ROM/CD img selected.");
  465. goto out;
  466. case PM_BAD_CD:
  467. menu_update_msg("Invalid CD image");
  468. goto out;
  469. case PM_BAD_CD_NO_BIOS:
  470. // find_bios() prints a message
  471. goto out;
  472. case PM_ERROR:
  473. menu_update_msg("Load error");
  474. goto out;
  475. default:
  476. break;
  477. }
  478. // make quirks visible in UI
  479. if (PicoIn.quirks & PQUIRK_FORCE_6BTN)
  480. currentConfig.input_dev0 = PICO_INPUT_PAD_6BTN;
  481. menu_romload_end();
  482. menu_romload_started = 0;
  483. if (PicoPatches) {
  484. PicoPatchPrepare();
  485. PicoPatchApply();
  486. }
  487. // additional movie stuff
  488. if (movie_data)
  489. {
  490. enum input_device indev = (movie_data[0x14] == '6') ?
  491. PICO_INPUT_PAD_6BTN : PICO_INPUT_PAD_3BTN;
  492. PicoSetInputDevice(0, indev);
  493. PicoSetInputDevice(1, indev);
  494. PicoIn.opt |= POPT_DIS_VDP_FIFO; // no VDP fifo timing
  495. if (movie_data[0xF] >= 'A') {
  496. if (movie_data[0x16] & 0x80) {
  497. PicoIn.regionOverride = 8;
  498. } else {
  499. PicoIn.regionOverride = 4;
  500. }
  501. PicoReset();
  502. // TODO: bits 6 & 5
  503. }
  504. movie_data[0x18+30] = 0;
  505. emu_status_msg("MOVIE: %s", (char *) &movie_data[0x18]);
  506. }
  507. else
  508. {
  509. system_announce();
  510. PicoIn.opt &= ~POPT_DIS_VDP_FIFO;
  511. }
  512. /* Set input map */
  513. if (PicoIn.AHW & PAHW_SMS) {
  514. printf("plat set sms input\n");
  515. plat_set_sms_input();
  516. }
  517. else{
  518. plat_set_genesis_input();
  519. }
  520. strncpy(rom_fname_loaded, rom_fname, sizeof(rom_fname_loaded)-1);
  521. rom_fname_loaded[sizeof(rom_fname_loaded)-1] = 0;
  522. // load SRAM for this ROM
  523. if (currentConfig.EmuOpt & EOPT_EN_SRAM)
  524. emu_save_load_game(1, 1);
  525. // state autoload?
  526. if (autoload) {
  527. int time, newest = 0, newest_slot = -1;
  528. int slot;
  529. for (slot = 0; slot < 10; slot++) {
  530. if (emu_check_save_file(slot, &time)) {
  531. if (time > newest) {
  532. newest = time;
  533. newest_slot = slot;
  534. }
  535. }
  536. }
  537. if (newest_slot >= 0) {
  538. lprintf("autoload slot %d\n", newest_slot);
  539. state_slot = newest_slot;
  540. emu_save_load_game(1, 0);
  541. }
  542. else {
  543. lprintf("no save to autoload.\n");
  544. }
  545. }
  546. retval = 1;
  547. out:
  548. if (menu_romload_started)
  549. menu_romload_end();
  550. free(rom_fname);
  551. return retval;
  552. }
  553. int emu_swap_cd(const char *fname)
  554. {
  555. enum cd_track_type cd_type;
  556. int ret = -1;
  557. cd_type = PicoCdCheck(fname, NULL);
  558. if (cd_type != CT_UNKNOWN)
  559. ret = cdd_load(fname, cd_type);
  560. if (ret != 0) {
  561. menu_update_msg("Load failed, invalid CD image?");
  562. return 0;
  563. }
  564. strncpy(rom_fname_loaded, fname, sizeof(rom_fname_loaded)-1);
  565. rom_fname_loaded[sizeof(rom_fname_loaded) - 1] = 0;
  566. return 1;
  567. }
  568. // <base dir><end>
  569. void emu_make_path(char *buff, const char *end, int size)
  570. {
  571. int pos, end_len;
  572. end_len = strlen(end);
  573. pos = plat_get_root_dir(buff, size);
  574. strncpy(buff + pos, end, size - pos);
  575. buff[size - 1] = 0;
  576. if (pos + end_len > size - 1)
  577. lprintf("Warning: path truncated: %s\n", buff);
  578. }
  579. static void make_config_cfg(char *cfg_buff_512)
  580. {
  581. emu_make_path(cfg_buff_512, PicoConfigFile, 512-6);
  582. if (config_slot != 0)
  583. {
  584. char *p = strrchr(cfg_buff_512, '.');
  585. if (p == NULL)
  586. p = cfg_buff_512 + strlen(cfg_buff_512);
  587. sprintf(p, ".%i.cfg", config_slot);
  588. }
  589. cfg_buff_512[511] = 0;
  590. }
  591. void emu_prep_defconfig(void)
  592. {
  593. memset(&defaultConfig, 0, sizeof(defaultConfig));
  594. defaultConfig.EmuOpt = EOPT_EN_SRAM | EOPT_EN_SOUND | EOPT_16BPP |
  595. EOPT_GZIP_SAVES | 0x10/*?*/;
  596. defaultConfig.s_PicoOpt = POPT_EN_YM2413|POPT_EN_STEREO|POPT_EN_FM|POPT_EN_PSG|POPT_EN_Z80 |
  597. POPT_EN_MCD_PCM|POPT_EN_MCD_CDDA|POPT_EN_MCD_GFX |
  598. POPT_EN_DRC|POPT_ACC_SPRITES |
  599. POPT_EN_32X|POPT_EN_PWM;
  600. defaultConfig.s_PsndRate = 44100;
  601. defaultConfig.s_PicoRegion = 0; // auto
  602. defaultConfig.s_PicoAutoRgnOrder = 0x184; // US, EU, JP
  603. defaultConfig.s_PicoCDBuffers = 0;
  604. defaultConfig.s_PicoSndFilterAlpha = 0x10000 * 60 / 100;
  605. defaultConfig.confirm_save = EOPT_CONFIRM_SAVE;
  606. defaultConfig.Frameskip = -1; // auto
  607. defaultConfig.input_dev0 = PICO_INPUT_PAD_3BTN;
  608. defaultConfig.input_dev1 = PICO_INPUT_PAD_3BTN;
  609. defaultConfig.volume = 50;
  610. //defaultConfig.volume = 99;
  611. defaultConfig.gamma = 100;
  612. defaultConfig.scaling = 0;
  613. defaultConfig.turbo_rate = 15;
  614. defaultConfig.msh2_khz = PICO_MSH2_HZ / 1000;
  615. defaultConfig.ssh2_khz = PICO_SSH2_HZ / 1000;
  616. defaultConfig.max_skip = 4;
  617. // platform specific overrides
  618. pemu_prep_defconfig();
  619. }
  620. void emu_set_defconfig(void)
  621. {
  622. memcpy(&currentConfig, &defaultConfig, sizeof(currentConfig));
  623. PicoIn.opt = currentConfig.s_PicoOpt;
  624. PicoIn.sndRate = currentConfig.s_PsndRate;
  625. PicoIn.regionOverride = currentConfig.s_PicoRegion;
  626. PicoIn.autoRgnOrder = currentConfig.s_PicoAutoRgnOrder;
  627. PicoIn.sndFilterAlpha = currentConfig.s_PicoSndFilterAlpha;
  628. }
  629. int emu_read_config(const char *rom_fname, int no_defaults)
  630. {
  631. char cfg[512];
  632. int ret;
  633. if (!no_defaults)
  634. emu_set_defconfig();
  635. if (rom_fname == NULL)
  636. {
  637. // global config
  638. make_config_cfg(cfg);
  639. ret = config_readsect(cfg, NULL);
  640. }
  641. else
  642. {
  643. char ext[16];
  644. int vol;
  645. if (config_slot != 0)
  646. snprintf(ext, sizeof(ext), ".%i.cfg", config_slot);
  647. else
  648. strcpy(ext, ".cfg");
  649. fname_ext(cfg, sizeof(cfg), "cfg"PATH_SEP, ext, rom_fname); // gamepath/gamename.cfg
  650. // read user's config
  651. vol = currentConfig.volume;
  652. ret = config_readsect(cfg, NULL);
  653. currentConfig.volume = vol; // make vol global (bah)
  654. if (ret != 0)
  655. {
  656. // read global config, and apply game_def.cfg on top
  657. make_config_cfg(cfg); // $HOME/.picodrive/config2.cfg
  658. config_readsect(cfg, NULL);
  659. emu_make_path(cfg, "game_def.cfg", sizeof(cfg)); // $HOME/.picodrive/game_def.cfg
  660. ret = config_readsect(cfg, emu_make_rom_id(rom_fname));
  661. }
  662. }
  663. pemu_validate_config();
  664. PicoIn.overclockM68k = currentConfig.overclock_68k;
  665. // some sanity checks
  666. if (currentConfig.volume < 0 || currentConfig.volume > 99)
  667. currentConfig.volume = 50;
  668. if (ret == 0)
  669. config_slot_current = config_slot;
  670. return (ret == 0);
  671. }
  672. int emu_write_config(int is_game)
  673. {
  674. char cfg[512];
  675. int ret, write_lrom = 0;
  676. if (!is_game)
  677. {
  678. make_config_cfg(cfg);
  679. write_lrom = 1;
  680. } else {
  681. char ext[16];
  682. if (config_slot != 0)
  683. snprintf(ext, sizeof(ext), ".%i.cfg", config_slot);
  684. else
  685. strcpy(ext, ".cfg");
  686. romfname_ext(cfg, sizeof(cfg), "cfg"PATH_SEP, ext);
  687. }
  688. lprintf("emu_write_config: %s ", cfg);
  689. ret = config_write(cfg);
  690. if (write_lrom) config_writelrom(cfg);
  691. #ifdef __GP2X__
  692. sync();
  693. #endif
  694. lprintf((ret == 0) ? "(ok)\n" : "(failed)\n");
  695. if (ret == 0) config_slot_current = config_slot;
  696. return ret == 0;
  697. }
  698. /* always using built-in font */
  699. #define mk_text_out(name, type, val, topleft, step_x, step_y) \
  700. void name(int x, int y, const char *text) \
  701. { \
  702. int i, l, len = strlen(text); \
  703. type *screen = (type *)(topleft) + x * step_x + y * step_y; \
  704. \
  705. for (i = 0; i < len; i++, screen += 8 * step_x) \
  706. { \
  707. for (l = 0; l < 8; l++) \
  708. { \
  709. unsigned char fd = fontdata8x8[text[i] * 8 + l];\
  710. type *s = screen + l * step_y; \
  711. if (fd&0x80) s[step_x * 0] = val; \
  712. if (fd&0x40) s[step_x * 1] = val; \
  713. if (fd&0x20) s[step_x * 2] = val; \
  714. if (fd&0x10) s[step_x * 3] = val; \
  715. if (fd&0x08) s[step_x * 4] = val; \
  716. if (fd&0x04) s[step_x * 5] = val; \
  717. if (fd&0x02) s[step_x * 6] = val; \
  718. if (fd&0x01) s[step_x * 7] = val; \
  719. } \
  720. } \
  721. }
  722. mk_text_out(emu_text_out8, unsigned char, 0xf0, g_screen_ptr, 1, g_screen_ppitch)
  723. mk_text_out(emu_text_out16, unsigned short, 0xffff, g_screen_ptr, 1, g_screen_ppitch)
  724. mk_text_out(emu_text_out8_rot, unsigned char, 0xf0,
  725. (char *)g_screen_ptr + (g_screen_ppitch - 1) * g_screen_height, -g_screen_height, 1)
  726. mk_text_out(emu_text_out16_rot, unsigned short, 0xffff,
  727. (short *)g_screen_ptr + (g_screen_ppitch - 1) * g_screen_height, -g_screen_height, 1)
  728. #undef mk_text_out
  729. void emu_osd_text16(int x, int y, const char *text)
  730. {
  731. int len = strlen(text) * 8;
  732. int i, h;
  733. len++;
  734. if (x + len > g_screen_width)
  735. len = g_screen_width - x;
  736. for (h = 0; h < 8; h++) {
  737. unsigned short *p;
  738. p = (unsigned short *)g_screen_ptr
  739. + x + g_screen_ppitch * (y + h);
  740. for (i = len; i > 0; i--, p++)
  741. *p = (*p >> 2) & 0x39e7;
  742. }
  743. emu_text_out16(x, y, text);
  744. }
  745. static void update_movie(void)
  746. {
  747. int offs = Pico.m.frame_count*3 + 0x40;
  748. if (offs+3 > movie_size) {
  749. free(movie_data);
  750. movie_data = 0;
  751. emu_status_msg("END OF MOVIE.");
  752. lprintf("END OF MOVIE.\n");
  753. } else {
  754. // MXYZ SACB RLDU
  755. PicoIn.pad[0] = ~movie_data[offs] & 0x8f; // ! SCBA RLDU
  756. if(!(movie_data[offs] & 0x10)) PicoIn.pad[0] |= 0x40; // C
  757. if(!(movie_data[offs] & 0x20)) PicoIn.pad[0] |= 0x10; // A
  758. if(!(movie_data[offs] & 0x40)) PicoIn.pad[0] |= 0x20; // B
  759. PicoIn.pad[1] = ~movie_data[offs+1] & 0x8f; // ! SCBA RLDU
  760. if(!(movie_data[offs+1] & 0x10)) PicoIn.pad[1] |= 0x40; // C
  761. if(!(movie_data[offs+1] & 0x20)) PicoIn.pad[1] |= 0x10; // A
  762. if(!(movie_data[offs+1] & 0x40)) PicoIn.pad[1] |= 0x20; // B
  763. PicoIn.pad[0] |= (~movie_data[offs+2] & 0x0A) << 8; // ! MZYX
  764. if(!(movie_data[offs+2] & 0x01)) PicoIn.pad[0] |= 0x0400; // X
  765. if(!(movie_data[offs+2] & 0x04)) PicoIn.pad[0] |= 0x0100; // Z
  766. PicoIn.pad[1] |= (~movie_data[offs+2] & 0xA0) << 4; // ! MZYX
  767. if(!(movie_data[offs+2] & 0x10)) PicoIn.pad[1] |= 0x0400; // X
  768. if(!(movie_data[offs+2] & 0x40)) PicoIn.pad[1] |= 0x0100; // Z
  769. }
  770. }
  771. static int try_ropen_file(const char *fname, int *time)
  772. {
  773. struct stat st;
  774. FILE *f;
  775. f = fopen(fname, "rb");
  776. if (f) {
  777. if (time != NULL) {
  778. *time = 0;
  779. if (fstat(fileno(f), &st) == 0)
  780. *time = (int)st.st_mtime;
  781. }
  782. fclose(f);
  783. return 1;
  784. }
  785. return 0;
  786. }
  787. char *emu_get_save_fname(int load, int is_sram, int slot, int *time)
  788. {
  789. char *saveFname = static_buff;
  790. char ext[16];
  791. if (is_sram)
  792. {
  793. strcpy(ext, (PicoIn.AHW & PAHW_MCD) ? ".brm" : ".srm");
  794. romfname_ext(saveFname, sizeof(static_buff),
  795. (PicoIn.AHW & PAHW_MCD) ? "brm"PATH_SEP : "srm"PATH_SEP, ext);
  796. if (!load)
  797. return saveFname;
  798. if (try_ropen_file(saveFname, time))
  799. return saveFname;
  800. romfname_ext(saveFname, sizeof(static_buff), NULL, ext);
  801. if (try_ropen_file(saveFname, time))
  802. return saveFname;
  803. }
  804. else
  805. {
  806. const char *ext_main = (currentConfig.EmuOpt & EOPT_GZIP_SAVES) ? ".mds.gz" : ".mds";
  807. const char *ext_othr = (currentConfig.EmuOpt & EOPT_GZIP_SAVES) ? ".mds" : ".mds.gz";
  808. ext[0] = 0;
  809. if (slot > 0 && slot < 10)
  810. sprintf(ext, ".%i", slot);
  811. strcat(ext, ext_main);
  812. if (!load) {
  813. romfname_ext(saveFname, sizeof(static_buff), "mds" PATH_SEP, ext);
  814. return saveFname;
  815. }
  816. else {
  817. romfname_ext(saveFname, sizeof(static_buff), "mds" PATH_SEP, ext);
  818. if (try_ropen_file(saveFname, time))
  819. return saveFname;
  820. romfname_ext(saveFname, sizeof(static_buff), NULL, ext);
  821. if (try_ropen_file(saveFname, time))
  822. return saveFname;
  823. // try the other ext
  824. ext[0] = 0;
  825. if (slot > 0 && slot < 10)
  826. sprintf(ext, ".%i", slot);
  827. strcat(ext, ext_othr);
  828. romfname_ext(saveFname, sizeof(static_buff), "mds"PATH_SEP, ext);
  829. if (try_ropen_file(saveFname, time))
  830. return saveFname;
  831. }
  832. }
  833. return NULL;
  834. }
  835. int emu_check_save_file(int slot, int *time)
  836. {
  837. return emu_get_save_fname(1, 0, slot, time) ? 1 : 0;
  838. }
  839. int emu_save_load_game_from_file(int load, char *saveFname){
  840. int ret = PicoState(saveFname, !load);
  841. if (!ret) {
  842. //emu_status_msg(load ? "STATE LOADED" : "STATE SAVED");
  843. } else {
  844. //emu_status_msg(load ? "LOAD FAILED" : "SAVE FAILED");
  845. ret = -1;
  846. }
  847. return ret;
  848. }
  849. int emu_save_load_game(int load, int sram)
  850. {
  851. int ret = 0;
  852. char *saveFname;
  853. // make save filename
  854. saveFname = emu_get_save_fname(load, sram, state_slot, NULL);
  855. if (saveFname == NULL) {
  856. /*if (!sram)
  857. emu_status_msg(load ? "LOAD FAILED (missing file)" : "SAVE FAILED");*/
  858. return -1;
  859. }
  860. lprintf("saveLoad (%i, %i): %s\n", load, sram, saveFname);
  861. if (sram)
  862. {
  863. FILE *sramFile;
  864. int sram_size;
  865. unsigned char *sram_data;
  866. int truncate = 1;
  867. if (PicoIn.AHW & PAHW_MCD)
  868. {
  869. if (PicoIn.opt & POPT_EN_MCD_RAMCART) {
  870. sram_size = 0x12000;
  871. sram_data = Pico.sv.data;
  872. if (sram_data)
  873. memcpy(sram_data, Pico_mcd->bram, 0x2000);
  874. } else {
  875. sram_size = 0x2000;
  876. sram_data = Pico_mcd->bram;
  877. truncate = 0; // the .brm may contain RAM cart data after normal brm
  878. }
  879. } else {
  880. sram_size = Pico.sv.size;
  881. sram_data = Pico.sv.data;
  882. }
  883. if (sram_data == NULL)
  884. return 0; // cart saves forcefully disabled for this game
  885. if (load)
  886. {
  887. sramFile = fopen(saveFname, "rb");
  888. if (!sramFile)
  889. return -1;
  890. ret = fread(sram_data, 1, sram_size, sramFile);
  891. ret = ret > 0 ? 0 : -1;
  892. fclose(sramFile);
  893. if ((PicoIn.AHW & PAHW_MCD) && (PicoIn.opt&POPT_EN_MCD_RAMCART))
  894. memcpy(Pico_mcd->bram, sram_data, 0x2000);
  895. } else {
  896. // sram save needs some special processing
  897. // see if we have anything to save
  898. for (; sram_size > 0; sram_size--)
  899. if (sram_data[sram_size-1]) break;
  900. if (sram_size) {
  901. sramFile = fopen(saveFname, truncate ? "wb" : "r+b");
  902. if (!sramFile) sramFile = fopen(saveFname, "wb"); // retry
  903. if (!sramFile) return -1;
  904. ret = fwrite(sram_data, 1, sram_size, sramFile);
  905. ret = (ret != sram_size) ? -1 : 0;
  906. fclose(sramFile);
  907. #ifdef __GP2X__
  908. sync();
  909. #endif
  910. }
  911. }
  912. return ret;
  913. }
  914. else
  915. {
  916. ret = PicoState(saveFname, !load);
  917. if (!ret) {
  918. #ifdef __GP2X__
  919. if (!load) sync();
  920. #endif
  921. //emu_status_msg(load ? "STATE LOADED" : "STATE SAVED");
  922. } else {
  923. //emu_status_msg(load ? "LOAD FAILED" : "SAVE FAILED");
  924. ret = -1;
  925. }
  926. return ret;
  927. }
  928. }
  929. void emu_set_fastforward(int set_on)
  930. {
  931. static void *set_PsndOut = NULL;
  932. static int set_Frameskip, set_EmuOpt, is_on = 0;
  933. if (set_on && !is_on) {
  934. set_PsndOut = PicoIn.sndOut;
  935. set_Frameskip = currentConfig.Frameskip;
  936. set_EmuOpt = currentConfig.EmuOpt;
  937. PicoIn.sndOut = NULL;
  938. currentConfig.Frameskip = 8;
  939. currentConfig.EmuOpt &= ~4;
  940. currentConfig.EmuOpt |= EOPT_NO_FRMLIMIT;
  941. is_on = 1;
  942. emu_status_msg("FAST FORWARD");
  943. }
  944. else if (!set_on && is_on) {
  945. PicoIn.sndOut = set_PsndOut;
  946. currentConfig.Frameskip = set_Frameskip;
  947. currentConfig.EmuOpt = set_EmuOpt;
  948. PsndRerate(1);
  949. is_on = 0;
  950. // mainly to unbreak pcm
  951. if (PicoIn.AHW & PAHW_MCD)
  952. pcd_state_loaded();
  953. }
  954. }
  955. static void emu_tray_open(void)
  956. {
  957. engineState = PGS_TrayMenu;
  958. }
  959. static void emu_tray_close(void)
  960. {
  961. emu_status_msg("CD tray closed.");
  962. }
  963. void emu_32x_startup(void)
  964. {
  965. plat_video_toggle_renderer(0, 0); // HACK
  966. system_announce();
  967. }
  968. void emu_reset_game(void)
  969. {
  970. PicoReset();
  971. reset_timing = 1;
  972. }
  973. void run_events_pico(unsigned int events)
  974. {
  975. int lim_x;
  976. if (events & PEV_PICO_SWINP) {
  977. pico_inp_mode++;
  978. if (pico_inp_mode > 2)
  979. pico_inp_mode = 0;
  980. switch (pico_inp_mode) {
  981. case 2: emu_status_msg("Input: Pen on Pad"); break;
  982. case 1: emu_status_msg("Input: Pen on Storyware"); break;
  983. case 0: emu_status_msg("Input: Joystick");
  984. PicoPicohw.pen_pos[0] = PicoPicohw.pen_pos[1] = 0x8000;
  985. break;
  986. }
  987. }
  988. if (events & PEV_PICO_PPREV) {
  989. PicoPicohw.page--;
  990. if (PicoPicohw.page < 0)
  991. PicoPicohw.page = 0;
  992. emu_status_msg("Page %i", PicoPicohw.page);
  993. }
  994. if (events & PEV_PICO_PNEXT) {
  995. PicoPicohw.page++;
  996. if (PicoPicohw.page > 6)
  997. PicoPicohw.page = 6;
  998. emu_status_msg("Page %i", PicoPicohw.page);
  999. }
  1000. if (pico_inp_mode == 0)
  1001. return;
  1002. /* handle other input modes */
  1003. if (PicoIn.pad[0] & 1) pico_pen_y--;
  1004. if (PicoIn.pad[0] & 2) pico_pen_y++;
  1005. if (PicoIn.pad[0] & 4) pico_pen_x--;
  1006. if (PicoIn.pad[0] & 8) pico_pen_x++;
  1007. PicoIn.pad[0] &= ~0x0f; // release UDLR
  1008. lim_x = (Pico.video.reg[12]&1) ? 319 : 255;
  1009. if (pico_pen_y < 8)
  1010. pico_pen_y = 8;
  1011. if (pico_pen_y > 224 - PICO_PEN_ADJUST_Y)
  1012. pico_pen_y = 224 - PICO_PEN_ADJUST_Y;
  1013. if (pico_pen_x < 0)
  1014. pico_pen_x = 0;
  1015. if (pico_pen_x > lim_x - PICO_PEN_ADJUST_X)
  1016. pico_pen_x = lim_x - PICO_PEN_ADJUST_X;
  1017. PicoPicohw.pen_pos[0] = pico_pen_x;
  1018. if (!(Pico.video.reg[12] & 1))
  1019. PicoPicohw.pen_pos[0] += pico_pen_x / 4;
  1020. PicoPicohw.pen_pos[0] += 0x3c;
  1021. PicoPicohw.pen_pos[1] = pico_inp_mode == 1 ? (0x2f8 + pico_pen_y) : (0x1fc + pico_pen_y);
  1022. }
  1023. static void do_turbo(unsigned short *pad, int acts)
  1024. {
  1025. static int turbo_pad = 0;
  1026. static unsigned char turbo_cnt[3] = { 0, 0, 0 };
  1027. int inc = currentConfig.turbo_rate * 2;
  1028. if (acts & 0x1000) {
  1029. turbo_cnt[0] += inc;
  1030. if (turbo_cnt[0] >= 60)
  1031. turbo_pad ^= 0x10, turbo_cnt[0] = 0;
  1032. }
  1033. if (acts & 0x2000) {
  1034. turbo_cnt[1] += inc;
  1035. if (turbo_cnt[1] >= 60)
  1036. turbo_pad ^= 0x20, turbo_cnt[1] = 0;
  1037. }
  1038. if (acts & 0x4000) {
  1039. turbo_cnt[2] += inc;
  1040. if (turbo_cnt[2] >= 60)
  1041. turbo_pad ^= 0x40, turbo_cnt[2] = 0;
  1042. }
  1043. *pad |= turbo_pad & (acts >> 8);
  1044. }
  1045. static void run_events_ui(unsigned int which)
  1046. {
  1047. char shell_cmd[100];
  1048. FILE *fp;
  1049. //emu_action_old = emu_action;
  1050. //printf("New event: %d\n", which);
  1051. if (which & (PEV_STATE_LOAD|PEV_STATE_SAVE))
  1052. {
  1053. int do_it = 1;
  1054. if ( emu_check_save_file(state_slot, NULL) &&
  1055. (((which & PEV_STATE_LOAD) && (currentConfig.confirm_save & EOPT_CONFIRM_LOAD)) ||
  1056. ((which & PEV_STATE_SAVE) && (currentConfig.confirm_save & EOPT_CONFIRM_SAVE))) )
  1057. {
  1058. const char *nm;
  1059. char tmp[64];
  1060. int keys, len;
  1061. strcpy(tmp, (which & PEV_STATE_LOAD) ? "LOAD STATE? " : "OVERWRITE SAVE? ");
  1062. len = strlen(tmp);
  1063. nm = in_get_key_name(-1, -PBTN_MOK);
  1064. snprintf(tmp + len, sizeof(tmp) - len, "(%s=yes, ", nm);
  1065. len = strlen(tmp);
  1066. nm = in_get_key_name(-1, -PBTN_MBACK);
  1067. snprintf(tmp + len, sizeof(tmp) - len, "%s=no)", nm);
  1068. plat_status_msg_busy_first(tmp);
  1069. in_set_config_int(0, IN_CFG_BLOCKING, 1);
  1070. while (in_menu_wait_any(NULL, 50) & (PBTN_MOK | PBTN_MBACK))
  1071. ;
  1072. while ( !((keys = in_menu_wait_any(NULL, 50)) & (PBTN_MOK | PBTN_MBACK)))
  1073. ;
  1074. if (keys & PBTN_MBACK)
  1075. do_it = 0;
  1076. while (in_menu_wait_any(NULL, 50) & (PBTN_MOK | PBTN_MBACK))
  1077. ;
  1078. in_set_config_int(0, IN_CFG_BLOCKING, 0);
  1079. plat_status_msg_clear();
  1080. }
  1081. if (do_it) {
  1082. plat_status_msg_busy_first((which & PEV_STATE_LOAD) ? "LOADING STATE" : "SAVING STATE");
  1083. PicoStateProgressCB = plat_status_msg_busy_next;
  1084. emu_save_load_game((which & PEV_STATE_LOAD) ? 1 : 0, 0);
  1085. PicoStateProgressCB = NULL;
  1086. }
  1087. }
  1088. if (which & PEV_SWITCH_RND)
  1089. {
  1090. plat_video_toggle_renderer(1, 0);
  1091. }
  1092. if (which & PEV_VOL_DOWN)
  1093. {
  1094. printf("PEV_VOL_DOWN\r\n");
  1095. /// ----- Compute new value -----
  1096. volume_percentage = (volume_percentage < STEP_CHANGE_VOLUME)?
  1097. 0:(volume_percentage-STEP_CHANGE_VOLUME);
  1098. /// ----- HUD msg ------
  1099. char txt[100];
  1100. sprintf(txt, "VOLUME %d%%", volume_percentage);
  1101. plat_status_msg_busy_first(txt);
  1102. /// ----- Shell cmd ----
  1103. sprintf(shell_cmd, "%s %d", SHELL_CMD_VOLUME_SET, volume_percentage);
  1104. fp = popen(shell_cmd, "r");
  1105. if (fp == NULL) {
  1106. printf("Failed to run command %s\n", shell_cmd);
  1107. } else {
  1108. pclose(fp);
  1109. }
  1110. }
  1111. if (which & PEV_VOL_UP)
  1112. {
  1113. printf("PEV_VOL_UP\r\n");
  1114. /// ----- Compute new value -----
  1115. volume_percentage = (volume_percentage > 100 - STEP_CHANGE_VOLUME)?
  1116. 100:(volume_percentage+STEP_CHANGE_VOLUME);
  1117. /// ----- HUD msg ------
  1118. char txt[100];
  1119. sprintf(txt, "VOLUME %d%%", volume_percentage);
  1120. plat_status_msg_busy_first(txt);
  1121. /// ----- Shell cmd ----
  1122. sprintf(shell_cmd, "%s %d", SHELL_CMD_VOLUME_SET, volume_percentage);
  1123. fp = popen(shell_cmd, "r");
  1124. if (fp == NULL) {
  1125. printf("Failed to run command %s\n", shell_cmd);
  1126. } else {
  1127. pclose(fp);
  1128. }
  1129. }
  1130. if (which & PEV_BRIGHT_UP)
  1131. {
  1132. printf("PEV_BRIGHT_UP\r\n");
  1133. /// ----- Compute new value -----
  1134. brightness_percentage = (brightness_percentage > 100 - STEP_CHANGE_BRIGHTNESS)?
  1135. 100:(brightness_percentage+STEP_CHANGE_BRIGHTNESS);
  1136. /// ----- HUD msg ------
  1137. char txt[100];
  1138. sprintf(txt, "BRIGHTNESS %d%%", brightness_percentage);
  1139. plat_status_msg_busy_first(txt);
  1140. /// ----- Shell cmd ----
  1141. sprintf(shell_cmd, "%s %d", SHELL_CMD_BRIGHTNESS_SET, brightness_percentage);
  1142. fp = popen(shell_cmd, "r");
  1143. if (fp == NULL) {
  1144. printf("Failed to run command %s\n", shell_cmd);
  1145. } else {
  1146. pclose(fp);
  1147. }
  1148. }
  1149. if (which & PEV_BRIGHT_DOWN)
  1150. {
  1151. printf("PEV_BRIGHT_DOWN\r\n");
  1152. /// ----- Compute new value -----
  1153. brightness_percentage = (brightness_percentage < STEP_CHANGE_BRIGHTNESS)?
  1154. 0:(brightness_percentage-STEP_CHANGE_BRIGHTNESS);
  1155. /// ----- HUD msg ------
  1156. char txt[100];
  1157. sprintf(txt, "BRIGHTNESS %d%%", brightness_percentage);
  1158. plat_status_msg_busy_first(txt);
  1159. /// ----- Shell cmd ----
  1160. sprintf(shell_cmd, "%s %d", SHELL_CMD_BRIGHTNESS_SET, brightness_percentage);
  1161. fp = popen(shell_cmd, "r");
  1162. if (fp == NULL) {
  1163. printf("Failed to run command %s\n", shell_cmd);
  1164. } else {
  1165. pclose(fp);
  1166. }
  1167. }
  1168. if (which & PEV_AR_FACT_UP)
  1169. {
  1170. printf("PEV_AR_FACT_UP\r\n");
  1171. /// ----- Compute new value -----
  1172. if(aspect_ratio == ASPECT_RATIOS_TYPE_MANUAL){
  1173. aspect_ratio_factor_percent = (aspect_ratio_factor_percent+aspect_ratio_factor_step<100)?
  1174. aspect_ratio_factor_percent+aspect_ratio_factor_step:100;
  1175. need_screen_cleared = 1;
  1176. }
  1177. else{
  1178. aspect_ratio = ASPECT_RATIOS_TYPE_MANUAL;
  1179. }
  1180. aspect_ratio = ASPECT_RATIOS_TYPE_MANUAL;
  1181. /// ----- HUD msg ------
  1182. /*char txt[100];
  1183. sprintf(txt, " DISPLAY MODE: ZOOMED - %d%%", aspect_ratio_factor_percent);
  1184. plat_status_msg_busy_first(txt);*/
  1185. sprintf(shell_cmd, "%s %d \" DISPLAY MODE: ZOOMED %d%%%%\"",
  1186. SHELL_CMD_NOTIF_SET, NOTIF_SECONDS_DISP, aspect_ratio_factor_percent);
  1187. fp = popen(shell_cmd, "r");
  1188. if (fp == NULL) {
  1189. printf("Failed to run command %s\n", shell_cmd);
  1190. } else {
  1191. pclose(fp);
  1192. }
  1193. // Save config file
  1194. configfile_save(cfg_file_rom);
  1195. }
  1196. if (which & PEV_AR_FACT_DOWN)
  1197. {
  1198. printf("PEV_AR_FACT_DOWN\r\n");
  1199. /// ----- Compute new value -----
  1200. if(aspect_ratio == ASPECT_RATIOS_TYPE_MANUAL){
  1201. aspect_ratio_factor_percent = (aspect_ratio_factor_percent>aspect_ratio_factor_step)?
  1202. aspect_ratio_factor_percent-aspect_ratio_factor_step:0;
  1203. need_screen_cleared = 1;
  1204. }
  1205. else{
  1206. aspect_ratio = ASPECT_RATIOS_TYPE_MANUAL;
  1207. }
  1208. aspect_ratio = ASPECT_RATIOS_TYPE_MANUAL;
  1209. /// ----- HUD msg ------
  1210. /*char txt[100];
  1211. sprintf(txt, " DISPLAY MODE: ZOOMED - %d%%", aspect_ratio_factor_percent);
  1212. plat_status_msg_busy_first(txt);*/
  1213. sprintf(shell_cmd, "%s %d \" DISPLAY MODE: ZOOMED %d%%%%\"",
  1214. SHELL_CMD_NOTIF_SET, NOTIF_SECONDS_DISP, aspect_ratio_factor_percent);
  1215. fp = popen(shell_cmd, "r");
  1216. if (fp == NULL) {
  1217. printf("Failed to run command %s\n", shell_cmd);
  1218. } else {
  1219. pclose(fp);
  1220. }
  1221. // Save config file
  1222. configfile_save(cfg_file_rom);
  1223. }
  1224. if (which & PEV_DISPMODE)
  1225. {
  1226. printf("PEV_DISPMODE\r\n");
  1227. /// ----- Compute new value -----
  1228. aspect_ratio = (aspect_ratio+1)%NB_ASPECT_RATIOS_TYPES;
  1229. /// ----- HUD msg ------
  1230. //char txt[100];
  1231. if(aspect_ratio == ASPECT_RATIOS_TYPE_MANUAL){
  1232. //sprintf(txt, " DISPLAY MODE: ZOOMED - %d%%", aspect_ratio_factor_percent);
  1233. sprintf(shell_cmd, "%s %d \" DISPLAY MODE: ZOOMED %d%%%%\"",
  1234. SHELL_CMD_NOTIF_SET, NOTIF_SECONDS_DISP, aspect_ratio_factor_percent);
  1235. }
  1236. else{
  1237. //sprintf(txt, "DISPLAY MODE: %s", aspect_ratio_name[aspect_ratio]);
  1238. sprintf(shell_cmd, "%s %d \" DISPLAY MODE: %s\"",
  1239. SHELL_CMD_NOTIF_SET, NOTIF_SECONDS_DISP, aspect_ratio_name[aspect_ratio]);
  1240. }
  1241. //plat_status_msg_busy_first(txt);
  1242. fp = popen(shell_cmd, "r");
  1243. if (fp == NULL) {
  1244. printf("Failed to run command %s\n", shell_cmd);
  1245. } else {
  1246. pclose(fp);
  1247. }
  1248. // Save config file
  1249. configfile_save(cfg_file_rom);
  1250. }
  1251. if (which & (PEV_SSLOT_PREV|PEV_SSLOT_NEXT))
  1252. {
  1253. if (which & PEV_SSLOT_PREV) {
  1254. state_slot -= 1;
  1255. if (state_slot < 0)
  1256. state_slot = 9;
  1257. } else {
  1258. state_slot += 1;
  1259. if (state_slot > 9)
  1260. state_slot = 0;
  1261. }
  1262. emu_status_msg("SAVE SLOT %i [%s]", state_slot,
  1263. emu_check_save_file(state_slot, NULL) ? "USED" : "FREE");
  1264. }
  1265. if (which & PEV_RESET)
  1266. emu_reset_game();
  1267. if (which & PEV_MENU)
  1268. engineState = PGS_Menu;
  1269. }
  1270. void emu_update_input(void)
  1271. {
  1272. static int prev_events = 0;
  1273. int actions[IN_BINDTYPE_COUNT] = { 0, };
  1274. int pl_actions[2];
  1275. int events;
  1276. in_update(actions);
  1277. pl_actions[0] = actions[IN_BINDTYPE_PLAYER12];
  1278. pl_actions[1] = actions[IN_BINDTYPE_PLAYER12] >> 16;
  1279. PicoIn.pad[0] = pl_actions[0] & 0xfff;
  1280. PicoIn.pad[1] = pl_actions[1] & 0xfff;
  1281. if (pl_actions[0] & 0x7000)
  1282. do_turbo(&PicoIn.pad[0], pl_actions[0]);
  1283. if (pl_actions[1] & 0x7000)
  1284. do_turbo(&PicoIn.pad[1], pl_actions[1]);
  1285. events = actions[IN_BINDTYPE_EMU] & PEV_MASK;
  1286. // volume is treated in special way and triggered every frame
  1287. if (events & (PEV_VOL_DOWN|PEV_VOL_UP))
  1288. plat_update_volume(1, events & PEV_VOL_UP);
  1289. if ((events ^ prev_events) & PEV_FF) {
  1290. emu_set_fastforward(events & PEV_FF);
  1291. plat_update_volume(0, 0);
  1292. reset_timing = 1;
  1293. }
  1294. events &= ~prev_events;
  1295. /* SMS */
  1296. if (PicoIn.AHW == PAHW_PICO)
  1297. run_events_pico(events);
  1298. if (events)
  1299. run_events_ui(events);
  1300. if (movie_data)
  1301. update_movie();
  1302. prev_events = actions[IN_BINDTYPE_EMU] & PEV_MASK;
  1303. }
  1304. static void mkdir_path(char *path_with_reserve, int pos, const char *name)
  1305. {
  1306. strcpy(path_with_reserve + pos, name);
  1307. if (plat_is_dir(path_with_reserve))
  1308. return;
  1309. if (mkdir(path_with_reserve, 0777) < 0)
  1310. lprintf("failed to create: %s\n", path_with_reserve);
  1311. }
  1312. void emu_cmn_forced_frame(int no_scale, int do_emu, void *buf)
  1313. {
  1314. int po_old = PicoIn.opt;
  1315. int y;
  1316. for (y = 0; y < g_screen_height; y++)
  1317. memset32((short *)g_screen_ptr + g_screen_ppitch * y, 0,
  1318. g_screen_width * 2 / 4);
  1319. PicoIn.opt &= ~(POPT_ALT_RENDERER|POPT_EN_SOFTSCALE);
  1320. PicoIn.opt |= POPT_ACC_SPRITES;
  1321. if (!no_scale && currentConfig.scaling)
  1322. PicoIn.opt |= POPT_EN_SOFTSCALE;
  1323. PicoDrawSetOutFormat(PDF_RGB555, 1);
  1324. PicoDrawSetOutBuf(buf, g_screen_ppitch * 2);
  1325. Pico.m.dirtyPal = 1;
  1326. Pico.est.rendstatus |= PDRAW_DIRTY_SPRITES;
  1327. if (do_emu)
  1328. PicoFrame();
  1329. else
  1330. PicoFrameDrawOnly();
  1331. PicoIn.opt = po_old;
  1332. }
  1333. int emu_is_segaCD(){
  1334. return (PicoIn.AHW & PAHW_MCD);
  1335. }
  1336. /* Quick save and turn off the console */
  1337. void quick_save_and_poweroff()
  1338. {
  1339. FILE *fp;
  1340. printf("Save Instant Play file\n");
  1341. /* Send command to cancel any previously scheduled powerdown */
  1342. fp = popen(SHELL_CMD_POWERDOWN_HANDLE, "r");
  1343. if (fp == NULL)
  1344. {
  1345. /* Countdown is still ticking, so better do nothing
  1346. than start writing and get interrupted!
  1347. */
  1348. printf("Failed to cancel scheduled shutdown\n");
  1349. exit(0);
  1350. }
  1351. pclose(fp);
  1352. /* Save */
  1353. emu_save_load_game_from_file(0, quick_save_file);
  1354. /* Perform Instant Play save and shutdown */
  1355. execlp(SHELL_CMD_INSTANT_PLAY, SHELL_CMD_INSTANT_PLAY,
  1356. "save", prog_name, "-loadStateFile", quick_save_file, mRomName, NULL);
  1357. /* Should not be reached */
  1358. printf("Failed to perform Instant Play save and shutdown\n");
  1359. /* Exit Emulator */
  1360. exit(0);
  1361. }
  1362. void emu_init(void)
  1363. {
  1364. char path[512];
  1365. int pos;
  1366. #if 0
  1367. // FIXME: handle through menu, etc
  1368. FILE *f;
  1369. f = fopen("32X_M_BIOS.BIN", "rb");
  1370. p32x_bios_m = malloc(2048);
  1371. fread(p32x_bios_m, 1, 2048, f);
  1372. fclose(f);
  1373. f = fopen("32X_S_BIOS.BIN", "rb");
  1374. p32x_bios_s = malloc(1024);
  1375. fread(p32x_bios_s, 1, 1024, f);
  1376. fclose(f);
  1377. #endif
  1378. /* make dirs for saves */
  1379. pos = plat_get_root_dir(path, sizeof(path) - 4);
  1380. mkdir_path(path, pos, "mds");
  1381. mkdir_path(path, pos, "srm");
  1382. mkdir_path(path, pos, "brm");
  1383. mkdir_path(path, pos, "cfg");
  1384. pprof_init();
  1385. make_config_cfg(path);
  1386. config_readlrom(path);
  1387. PicoInit();
  1388. PicoIn.osdMessage = plat_status_msg_busy_next;
  1389. PicoIn.mcdTrayOpen = emu_tray_open;
  1390. PicoIn.mcdTrayClose = emu_tray_close;
  1391. sndout_init();
  1392. }
  1393. void emu_finish(void)
  1394. {
  1395. // save SRAM
  1396. if ((currentConfig.EmuOpt & EOPT_EN_SRAM) && Pico.sv.changed) {
  1397. emu_save_load_game(0, 1);
  1398. Pico.sv.changed = 0;
  1399. }
  1400. if (!(currentConfig.EmuOpt & EOPT_NO_AUTOSVCFG)) {
  1401. char cfg[512];
  1402. make_config_cfg(cfg);
  1403. config_writelrom(cfg);
  1404. #ifdef __GP2X__
  1405. sync();
  1406. #endif
  1407. }
  1408. pprof_finish();
  1409. PicoExit();
  1410. sndout_exit();
  1411. }
  1412. static void snd_write_nonblocking(int len)
  1413. {
  1414. sndout_write_nb(PicoIn.sndOut, len);
  1415. }
  1416. void emu_sound_start(void)
  1417. {
  1418. PicoIn.sndOut = NULL;
  1419. if (currentConfig.EmuOpt & EOPT_EN_SOUND)
  1420. {
  1421. int is_stereo = (PicoIn.opt & POPT_EN_STEREO) ? 1 : 0;
  1422. /// Hard Bypass Stereo to mono
  1423. //is_stereo = 0;
  1424. PsndRerate(Pico.m.frame_count ? 1 : 0);
  1425. printf("starting audio: %i len: %i stereo: %i, pal: %i\n",
  1426. PicoIn.sndRate, Pico.snd.len, is_stereo, Pico.m.pal);
  1427. sndout_start(PicoIn.sndRate, is_stereo);
  1428. PicoIn.writeSound = snd_write_nonblocking;
  1429. plat_update_volume(0, 0);
  1430. memset(sndBuffer, 0, sizeof(sndBuffer));
  1431. PicoIn.sndOut = sndBuffer;
  1432. }
  1433. }
  1434. void emu_sound_stop(void)
  1435. {
  1436. sndout_stop();
  1437. }
  1438. void emu_sound_wait(void)
  1439. {
  1440. sndout_wait();
  1441. }
  1442. static void emu_loop_prep(void)
  1443. {
  1444. static int pal_old = -1;
  1445. static int filter_old = -1;
  1446. if (currentConfig.CPUclock != plat_target_cpu_clock_get())
  1447. plat_target_cpu_clock_set(currentConfig.CPUclock);
  1448. if (Pico.m.pal != pal_old) {
  1449. plat_target_lcdrate_set(Pico.m.pal);
  1450. pal_old = Pico.m.pal;
  1451. }
  1452. if (currentConfig.filter != filter_old) {
  1453. plat_target_hwfilter_set(currentConfig.filter);
  1454. filter_old = currentConfig.filter;
  1455. }
  1456. plat_target_gamma_set(currentConfig.gamma, 0);
  1457. pemu_loop_prep();
  1458. }
  1459. /* our tick here is 1 us right now */
  1460. #define ms_to_ticks(x) (unsigned int)(x * 1000)
  1461. #define get_ticks() plat_get_ticks_us()
  1462. #define vsync_delay_x3 3*ms_to_ticks(1)
  1463. void emu_loop(void)
  1464. {
  1465. int frames_done, frames_shown; /* actual frames for fps counter */
  1466. int frame_nb = 0;
  1467. int target_frametime_x3;
  1468. unsigned int timestamp_x3 = 0;
  1469. unsigned int timestamp_aim_x3 = 0;
  1470. unsigned int timestamp_fps_x3 = 0;
  1471. char *notice_msg = NULL;
  1472. char fpsbuff[24];
  1473. int fskip_cnt = 0;
  1474. fpsbuff[0] = 0;
  1475. PicoLoopPrepare();
  1476. plat_video_loop_prepare();
  1477. emu_loop_prep();
  1478. pemu_sound_start();
  1479. /* number of ticks per frame */
  1480. if (Pico.m.pal)
  1481. target_frametime_x3 = 3 * ms_to_ticks(1000) / 50;
  1482. else
  1483. target_frametime_x3 = 3 * ms_to_ticks(1000) / 60;
  1484. reset_timing = 1;
  1485. frames_done = frames_shown = 0;
  1486. /* loop with resync every 1 sec. */
  1487. while (engineState == PGS_Running)
  1488. {
  1489. int skip = 0;
  1490. int diff;
  1491. pprof_start(main);
  1492. if (reset_timing) {
  1493. reset_timing = 0;
  1494. plat_video_wait_vsync();
  1495. timestamp_aim_x3 = get_ticks() * 3;
  1496. timestamp_fps_x3 = timestamp_aim_x3;
  1497. fskip_cnt = 0;
  1498. }
  1499. else if (currentConfig.EmuOpt & EOPT_NO_FRMLIMIT) {
  1500. timestamp_aim_x3 = get_ticks() * 3;
  1501. }
  1502. timestamp_x3 = get_ticks() * 3;
  1503. // show notice_msg message?
  1504. if (notice_msg_time != 0)
  1505. {
  1506. static int noticeMsgSum;
  1507. if (timestamp_x3 - ms_to_ticks(notice_msg_time) * 3
  1508. > ms_to_ticks(STATUS_MSG_TIMEOUT) * 3)
  1509. {
  1510. notice_msg_time = 0;
  1511. notice_msg = NULL;
  1512. plat_status_msg_clear();
  1513. }
  1514. else {
  1515. int sum = noticeMsg[0] + noticeMsg[1] + noticeMsg[2];
  1516. if (sum != noticeMsgSum) {
  1517. plat_status_msg_clear();
  1518. noticeMsgSum = sum;
  1519. }
  1520. notice_msg = noticeMsg;
  1521. }
  1522. }
  1523. // second changed?
  1524. if (timestamp_x3 - timestamp_fps_x3 >= ms_to_ticks(1000) * 3)
  1525. {
  1526. #define FUNKEY_RESYNCHRONIZE_AUDIO_SECS (5*60)
  1527. #ifdef FUNKEY_RESYNCHRONIZE_AUDIO_SECS
  1528. static unsigned int last_resync = 0, cur_sec=0;
  1529. if(cur_sec++ - last_resync >= FUNKEY_RESYNCHRONIZE_AUDIO_SECS){
  1530. last_resync = cur_sec;
  1531. /** Resync here (same as quitting ans relaunching loop for now) */
  1532. printf("Resync sound now\n");
  1533. emu_sound_stop();
  1534. pemu_sound_start();
  1535. }
  1536. #endif //FUNKEY_RESYNCHRONIZE_AUDIO_SECS
  1537. #ifdef BENCHMARK
  1538. static int bench = 0, bench_fps = 0, bench_fps_s = 0, bfp = 0, bf[4];
  1539. if (++bench == 10) {
  1540. bench = 0;
  1541. bench_fps_s = bench_fps;
  1542. bf[bfp++ & 3] = bench_fps;
  1543. bench_fps = 0;
  1544. }
  1545. bench_fps += frames_shown;
  1546. sprintf(fpsbuff, "%02i/%02i/%02i", frames_shown, bench_fps_s, (bf[0]+bf[1]+bf[2]+bf[3])>>2);
  1547. printf("%s\n", fpsbuff);
  1548. #else
  1549. if (currentConfig.EmuOpt & EOPT_SHOW_FPS || show_fps_bypass){
  1550. printf("%02i/%02i \n", frames_shown, frames_done);
  1551. snprintf(fpsbuff, 8, "%02i/%02i ", frames_shown, frames_done);
  1552. }
  1553. #endif
  1554. frames_shown = frames_done = 0;
  1555. timestamp_fps_x3 += ms_to_ticks(1000) * 3;
  1556. }
  1557. #ifdef PFRAMES
  1558. sprintf(fpsbuff, "%i", Pico.m.frame_count);
  1559. #endif
  1560. diff = timestamp_aim_x3 - timestamp_x3;
  1561. if (currentConfig.Frameskip >= 0) // frameskip enabled (or 0)
  1562. {
  1563. if (fskip_cnt < currentConfig.Frameskip) {
  1564. fskip_cnt++;
  1565. skip = 1;
  1566. }
  1567. else {
  1568. fskip_cnt = 0;
  1569. }
  1570. }
  1571. else if (diff < -target_frametime_x3)
  1572. {
  1573. /* no time left for this frame - skip */
  1574. /* limit auto frameskip to max_skip */
  1575. if (fskip_cnt < currentConfig.max_skip) {
  1576. fskip_cnt++;
  1577. skip = 1;
  1578. }
  1579. else {
  1580. fskip_cnt = 0;
  1581. }
  1582. } else
  1583. fskip_cnt = 0;
  1584. // don't go in debt too much
  1585. while (diff < -target_frametime_x3 * 3) {
  1586. timestamp_aim_x3 += target_frametime_x3;
  1587. diff = timestamp_aim_x3 - timestamp_x3;
  1588. }
  1589. /* Quick save and poweroff */
  1590. if(mQuickSaveAndPoweroff){
  1591. quick_save_and_poweroff();
  1592. mQuickSaveAndPoweroff = 0;
  1593. }
  1594. emu_update_input();
  1595. if (skip) {
  1596. int do_audio = diff > -target_frametime_x3 * 2;
  1597. PicoIn.skipFrame = do_audio ? 1 : 2;
  1598. PicoFrame();
  1599. PicoIn.skipFrame = 0;
  1600. }
  1601. else {
  1602. PicoFrame();
  1603. pemu_finalize_frame(fpsbuff, notice_msg);
  1604. frames_shown++;
  1605. }
  1606. frames_done++;
  1607. timestamp_aim_x3 += target_frametime_x3;
  1608. if (!skip && !flip_after_sync)
  1609. plat_video_flip();
  1610. /* frame limiter */
  1611. if (!skip && !reset_timing
  1612. && !(currentConfig.EmuOpt & (EOPT_NO_FRMLIMIT|EOPT_EXT_FRMLIMIT)))
  1613. {
  1614. unsigned int timestamp = get_ticks();
  1615. diff = timestamp_aim_x3 - timestamp * 3;
  1616. // sleep or vsync if we are still too fast
  1617. if (diff > target_frametime_x3 + vsync_delay_x3 && (currentConfig.EmuOpt & EOPT_VSYNC)) {
  1618. // we are too fast
  1619. plat_video_wait_vsync();
  1620. timestamp = get_ticks();
  1621. diff = timestamp * 3 - timestamp_aim_x3;
  1622. }
  1623. if (diff > target_frametime_x3 + vsync_delay_x3) {
  1624. // still too fast
  1625. plat_wait_till_us(timestamp + (diff - target_frametime_x3) / 3);
  1626. }
  1627. }
  1628. if (!skip && flip_after_sync)
  1629. plat_video_flip();
  1630. /* FOR SEGA CD */
  1631. /* Leave some time for the bios to load before starting a quick load at boot */
  1632. /* (Sega CD doesn't quick load at boot otherwise) */
  1633. /* Should have a much cleaner implementation thant this fix */
  1634. if((PicoIn.AHW & PAHW_MCD) && frame_nb >= 120){
  1635. /* Load slot */
  1636. if(load_state_slot != -1){
  1637. printf("LOADING FROM SLOT (SEGA CD) %d...\n", load_state_slot+1);
  1638. char fname[1024];
  1639. emu_save_load_game(1, 0);
  1640. printf("LOADED FROM SLOT (SEGA CD) %d\n", load_state_slot+1);
  1641. load_state_slot = -1;
  1642. }
  1643. if(need_quick_load != -1){
  1644. load_state_file = quick_save_file;
  1645. need_quick_load = -1;
  1646. }
  1647. /* Load file */
  1648. if(load_state_file != NULL){
  1649. printf("LOADING FROM FILE (SEGA CD) %s...\n", load_state_file);
  1650. emu_save_load_game_from_file(1, load_state_file);
  1651. printf("LOADED FROM SLOT (SEGA CD) %s\n", load_state_file);
  1652. load_state_file = NULL;
  1653. }
  1654. }
  1655. frame_nb++;
  1656. pprof_end(main);
  1657. }
  1658. emu_set_fastforward(0);
  1659. // save SRAM
  1660. if ((currentConfig.EmuOpt & EOPT_EN_SRAM) && Pico.sv.changed) {
  1661. plat_status_msg_busy_first("Writing SRAM/BRAM...");
  1662. emu_save_load_game(0, 1);
  1663. Pico.sv.changed = 0;
  1664. }
  1665. pemu_loop_end();
  1666. emu_sound_stop();
  1667. }