emu.c 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716
  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 <stdarg.h>
  11. #ifndef NO_SYNC
  12. #include <unistd.h>
  13. #endif
  14. #include "../libpicofe/posix.h"
  15. #include "../libpicofe/input.h"
  16. #include "../libpicofe/fonts.h"
  17. #include "../libpicofe/sndout.h"
  18. #include "../libpicofe/lprintf.h"
  19. #include "../libpicofe/plat.h"
  20. #include "emu.h"
  21. #include "input_pico.h"
  22. #include "menu_pico.h"
  23. #include "config_file.h"
  24. #include <pico/pico_int.h>
  25. #include <pico/patch.h>
  26. #include <pico/cd/cue.h>
  27. #define STATUS_MSG_TIMEOUT 2000
  28. void *g_screen_ptr;
  29. #if !SCREEN_SIZE_FIXED
  30. int g_screen_width = SCREEN_WIDTH;
  31. int g_screen_height = SCREEN_HEIGHT;
  32. #endif
  33. char *PicoConfigFile = "config.cfg";
  34. currentConfig_t currentConfig, defaultConfig;
  35. int state_slot = 0;
  36. int config_slot = 0, config_slot_current = 0;
  37. int pico_pen_x = 320/2, pico_pen_y = 240/2;
  38. int pico_inp_mode = 0;
  39. int engineState = PGS_Menu;
  40. static short __attribute__((aligned(4))) sndBuffer[2*44100/50];
  41. /* tmp buff to reduce stack usage for plats with small stack */
  42. static char static_buff[512];
  43. const char *rom_fname_reload;
  44. char rom_fname_loaded[512];
  45. int rom_loaded = 0;
  46. int reset_timing = 0;
  47. static unsigned int notice_msg_time; /* when started showing */
  48. static char noticeMsg[40];
  49. unsigned char *movie_data = NULL;
  50. static int movie_size = 0;
  51. /* don't use tolower() for easy old glibc binary compatibility */
  52. static void strlwr_(char *string)
  53. {
  54. char *p;
  55. for (p = string; *p; p++)
  56. if ('A' <= *p && *p <= 'Z')
  57. *p += 'a' - 'A';
  58. }
  59. static int try_rfn_cut(char *fname)
  60. {
  61. FILE *tmp;
  62. char *p;
  63. p = fname + strlen(fname) - 1;
  64. for (; p > fname; p--)
  65. if (*p == '.') break;
  66. *p = 0;
  67. if((tmp = fopen(fname, "rb"))) {
  68. fclose(tmp);
  69. return 1;
  70. }
  71. return 0;
  72. }
  73. static void get_ext(const char *file, char *ext)
  74. {
  75. const char *p;
  76. p = file + strlen(file) - 4;
  77. if (p < file) p = file;
  78. strncpy(ext, p, 4);
  79. ext[4] = 0;
  80. strlwr_(ext);
  81. }
  82. static void fname_ext(char *dst, int dstlen, const char *prefix, const char *ext, const char *fname)
  83. {
  84. int prefix_len = 0;
  85. const char *p;
  86. *dst = 0;
  87. if (prefix) {
  88. int len = plat_get_root_dir(dst, dstlen);
  89. strcpy(dst + len, prefix);
  90. prefix_len = len + strlen(prefix);
  91. }
  92. p = fname + strlen(fname) - 1;
  93. for (; p >= fname && *p != PATH_SEP_C; p--)
  94. ;
  95. p++;
  96. strncpy(dst + prefix_len, p, dstlen - prefix_len - 1);
  97. dst[dstlen - 8] = 0;
  98. if (dst[strlen(dst) - 4] == '.')
  99. dst[strlen(dst) - 4] = 0;
  100. if (ext)
  101. strcat(dst, ext);
  102. }
  103. static void romfname_ext(char *dst, int dstlen, const char *prefix, const char *ext)
  104. {
  105. fname_ext(dst, dstlen, prefix, ext, rom_fname_loaded);
  106. }
  107. void emu_status_msg(const char *format, ...)
  108. {
  109. va_list vl;
  110. int ret;
  111. va_start(vl, format);
  112. ret = vsnprintf(noticeMsg, sizeof(noticeMsg), format, vl);
  113. va_end(vl);
  114. /* be sure old text gets overwritten */
  115. for (; ret < 28; ret++)
  116. noticeMsg[ret] = ' ';
  117. noticeMsg[ret] = 0;
  118. notice_msg_time = plat_get_ticks_ms();
  119. }
  120. static const char * const biosfiles_us[] = { "us_scd1_9210", "us_scd2_9306", "SegaCDBIOS9303" };
  121. static const char * const biosfiles_eu[] = { "eu_mcd1_9210", "eu_mcd2_9306", "eu_mcd2_9303" };
  122. static const char * const biosfiles_jp[] = { "jp_mcd1_9112", "jp_mcd1_9111" };
  123. static int find_bios(int region, const char **bios_file)
  124. {
  125. int i, count;
  126. const char * const *files;
  127. FILE *f = NULL;
  128. if (region == 4) { // US
  129. files = biosfiles_us;
  130. count = sizeof(biosfiles_us) / sizeof(char *);
  131. } else if (region == 8) { // EU
  132. files = biosfiles_eu;
  133. count = sizeof(biosfiles_eu) / sizeof(char *);
  134. } else if (region == 1 || region == 2) {
  135. files = biosfiles_jp;
  136. count = sizeof(biosfiles_jp) / sizeof(char *);
  137. } else {
  138. return 0;
  139. }
  140. for (i = 0; i < count; i++)
  141. {
  142. emu_make_path(static_buff, files[i], sizeof(static_buff) - 4);
  143. strcat(static_buff, ".bin");
  144. f = fopen(static_buff, "rb");
  145. if (f) break;
  146. static_buff[strlen(static_buff) - 4] = 0;
  147. strcat(static_buff, ".zip");
  148. f = fopen(static_buff, "rb");
  149. if (f) break;
  150. }
  151. if (f) {
  152. lprintf("using bios: %s\n", static_buff);
  153. fclose(f);
  154. if (bios_file)
  155. *bios_file = static_buff;
  156. return 1;
  157. } else {
  158. sprintf(static_buff, "no %s BIOS files found, read docs",
  159. region != 4 ? (region == 8 ? "EU" : "JAP") : "USA");
  160. menu_update_msg(static_buff);
  161. return 0;
  162. }
  163. }
  164. /* check if the name begins with BIOS name */
  165. /*
  166. static int emu_isBios(const char *name)
  167. {
  168. int i;
  169. for (i = 0; i < sizeof(biosfiles_us)/sizeof(biosfiles_us[0]); i++)
  170. if (strstr(name, biosfiles_us[i]) != NULL) return 1;
  171. for (i = 0; i < sizeof(biosfiles_eu)/sizeof(biosfiles_eu[0]); i++)
  172. if (strstr(name, biosfiles_eu[i]) != NULL) return 1;
  173. for (i = 0; i < sizeof(biosfiles_jp)/sizeof(biosfiles_jp[0]); i++)
  174. if (strstr(name, biosfiles_jp[i]) != NULL) return 1;
  175. return 0;
  176. }
  177. */
  178. static unsigned char id_header[0x100];
  179. /* checks if fname points to valid MegaCD image */
  180. static int emu_cd_check(int *pregion, const char *fname_in)
  181. {
  182. const char *fname = fname_in;
  183. unsigned char buf[32];
  184. pm_file *cd_f;
  185. int region = 4; // 1: Japan, 4: US, 8: Europe
  186. char ext[5];
  187. cue_track_type type = CT_UNKNOWN;
  188. cue_data_t *cue_data = NULL;
  189. get_ext(fname_in, ext);
  190. if (strcasecmp(ext, ".cue") == 0) {
  191. cue_data = cue_parse(fname_in);
  192. if (cue_data != NULL) {
  193. fname = cue_data->tracks[1].fname;
  194. type = cue_data->tracks[1].type;
  195. }
  196. else
  197. return -1;
  198. }
  199. cd_f = pm_open(fname);
  200. if (cue_data != NULL)
  201. cue_destroy(cue_data);
  202. if (cd_f == NULL) return 0; // let the upper level handle this
  203. if (pm_read(buf, 32, cd_f) != 32) {
  204. pm_close(cd_f);
  205. return -1;
  206. }
  207. if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x00, 14)) {
  208. if (type && type != CT_ISO)
  209. elprintf(EL_STATUS, ".cue has wrong type: %i", type);
  210. type = CT_ISO; // Sega CD (ISO)
  211. }
  212. if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x10, 14)) {
  213. if (type && type != CT_BIN)
  214. elprintf(EL_STATUS, ".cue has wrong type: %i", type);
  215. type = CT_BIN; // Sega CD (BIN)
  216. }
  217. if (type == CT_UNKNOWN) {
  218. pm_close(cd_f);
  219. return 0;
  220. }
  221. pm_seek(cd_f, (type == CT_ISO) ? 0x100 : 0x110, SEEK_SET);
  222. pm_read(id_header, sizeof(id_header), cd_f);
  223. /* it seems we have a CD image here. Try to detect region now.. */
  224. pm_seek(cd_f, (type == CT_ISO) ? 0x100+0x10B : 0x110+0x10B, SEEK_SET);
  225. pm_read(buf, 1, cd_f);
  226. pm_close(cd_f);
  227. if (buf[0] == 0x64) region = 8; // EU
  228. if (buf[0] == 0xa1) region = 1; // JAP
  229. lprintf("detected %s Sega/Mega CD image with %s region\n",
  230. type == CT_BIN ? "BIN" : "ISO", region != 4 ? (region == 8 ? "EU" : "JAP") : "USA");
  231. if (pregion != NULL) *pregion = region;
  232. return type;
  233. }
  234. static int detect_media(const char *fname)
  235. {
  236. static const short sms_offsets[] = { 0x7ff0, 0x3ff0, 0x1ff0 };
  237. static const char *sms_exts[] = { "sms", "gg", "sg" };
  238. static const char *md_exts[] = { "gen", "bin", "smd" };
  239. char buff0[32], buff[32];
  240. unsigned short *d16;
  241. pm_file *pmf;
  242. char ext[5];
  243. int i;
  244. get_ext(fname, ext);
  245. // detect wrong extensions
  246. if (!strcmp(ext, ".srm") || !strcmp(ext, "s.gz") || !strcmp(ext, ".mds")) // s.gz ~ .mds.gz
  247. return PM_BAD;
  248. /* don't believe in extensions, except .cue */
  249. if (strcasecmp(ext, ".cue") == 0)
  250. return PM_CD;
  251. pmf = pm_open(fname);
  252. if (pmf == NULL)
  253. return PM_BAD;
  254. if (pm_read(buff0, 32, pmf) != 32) {
  255. pm_close(pmf);
  256. return PM_BAD;
  257. }
  258. if (strncasecmp("SEGADISCSYSTEM", buff0 + 0x00, 14) == 0 ||
  259. strncasecmp("SEGADISCSYSTEM", buff0 + 0x10, 14) == 0) {
  260. pm_close(pmf);
  261. return PM_CD;
  262. }
  263. /* check for SMD evil */
  264. if (pmf->size >= 0x4200 && (pmf->size & 0x3fff) == 0x200) {
  265. if (pm_seek(pmf, sms_offsets[0] + 0x200, SEEK_SET) == sms_offsets[0] + 0x200 &&
  266. pm_read(buff, 16, pmf) == 16 &&
  267. strncmp("TMR SEGA", buff, 8) == 0)
  268. goto looks_like_sms;
  269. /* could parse further but don't bother */
  270. goto extension_check;
  271. }
  272. /* MD header? Act as TMSS BIOS here */
  273. if (pm_seek(pmf, 0x100, SEEK_SET) == 0x100 && pm_read(buff, 16, pmf) == 16) {
  274. if (strncmp(buff, "SEGA", 4) == 0 || strncmp(buff, " SEG", 4) == 0)
  275. goto looks_like_md;
  276. }
  277. for (i = 0; i < array_size(sms_offsets); i++) {
  278. if (pm_seek(pmf, sms_offsets[i], SEEK_SET) != sms_offsets[i])
  279. continue;
  280. if (pm_read(buff, 16, pmf) != 16)
  281. continue;
  282. if (strncmp("TMR SEGA", buff, 8) == 0)
  283. goto looks_like_sms;
  284. }
  285. extension_check:
  286. /* probably some headerless thing. Maybe check the extension after all. */
  287. for (i = 0; i < array_size(md_exts); i++)
  288. if (strcasecmp(pmf->ext, md_exts[i]) == 0)
  289. goto looks_like_md;
  290. for (i = 0; i < array_size(sms_exts); i++)
  291. if (strcasecmp(pmf->ext, sms_exts[i]) == 0)
  292. goto looks_like_sms;
  293. /* If everything else fails, make a guess on the reset vector */
  294. d16 = (unsigned short *)(buff0 + 4);
  295. if ((((d16[0] << 16) | d16[1]) & 0xffffff) >= pmf->size) {
  296. lprintf("bad MD reset vector, assuming SMS\n");
  297. goto looks_like_sms;
  298. }
  299. looks_like_md:
  300. pm_close(pmf);
  301. return PM_MD_CART;
  302. looks_like_sms:
  303. pm_close(pmf);
  304. return PM_MARK3;
  305. }
  306. static int extract_text(char *dest, const unsigned char *src, int len, int swab)
  307. {
  308. char *p = dest;
  309. int i;
  310. if (swab) swab = 1;
  311. for (i = len - 1; i >= 0; i--)
  312. {
  313. if (src[i^swab] != ' ') break;
  314. }
  315. len = i + 1;
  316. for (i = 0; i < len; i++)
  317. {
  318. unsigned char s = src[i^swab];
  319. if (s >= 0x20 && s < 0x7f && s != '#' && s != '|' &&
  320. s != '[' && s != ']' && s != '\\')
  321. {
  322. *p++ = s;
  323. }
  324. else
  325. {
  326. sprintf(p, "\\%02x", s);
  327. p += 3;
  328. }
  329. }
  330. return p - dest;
  331. }
  332. static char *emu_make_rom_id(const char *fname)
  333. {
  334. static char id_string[3+0xe*3+0x3*3+0x30*3+3];
  335. int pos, swab = 1;
  336. if (PicoAHW & PAHW_MCD) {
  337. strcpy(id_string, "CD|");
  338. swab = 0;
  339. }
  340. else if (PicoAHW & PAHW_SMS)
  341. strcpy(id_string, "MS|");
  342. else strcpy(id_string, "MD|");
  343. pos = 3;
  344. if (!(PicoAHW & PAHW_SMS)) {
  345. pos += extract_text(id_string + pos, id_header + 0x80, 0x0e, swab); // serial
  346. id_string[pos] = '|'; pos++;
  347. pos += extract_text(id_string + pos, id_header + 0xf0, 0x03, swab); // region
  348. id_string[pos] = '|'; pos++;
  349. pos += extract_text(id_string + pos, id_header + 0x50, 0x30, swab); // overseas name
  350. id_string[pos] = 0;
  351. if (pos > 5)
  352. return id_string;
  353. pos = 3;
  354. }
  355. // can't find name in ROM, use filename
  356. fname_ext(id_string + 3, sizeof(id_string) - 3, NULL, NULL, fname);
  357. return id_string;
  358. }
  359. // buffer must be at least 150 byte long
  360. void emu_get_game_name(char *str150)
  361. {
  362. int ret, swab = (PicoAHW & PAHW_MCD) ? 0 : 1;
  363. char *s, *d;
  364. ret = extract_text(str150, id_header + 0x50, 0x30, swab); // overseas name
  365. for (s = d = str150 + 1; s < str150+ret; s++)
  366. {
  367. if (*s == 0) break;
  368. if (*s != ' ' || d[-1] != ' ')
  369. *d++ = *s;
  370. }
  371. *d = 0;
  372. }
  373. static void shutdown_MCD(void)
  374. {
  375. if ((PicoAHW & PAHW_MCD) && Pico_mcd != NULL)
  376. Stop_CD();
  377. PicoAHW &= ~PAHW_MCD;
  378. }
  379. static void system_announce(void)
  380. {
  381. const char *sys_name, *tv_standard, *extra = "";
  382. int fps;
  383. if (PicoAHW & PAHW_SMS) {
  384. sys_name = "Master System";
  385. #ifdef NO_SMS
  386. extra = " [no support]";
  387. #endif
  388. } else if (PicoAHW & PAHW_PICO) {
  389. sys_name = "Pico";
  390. } else if (PicoAHW & PAHW_MCD) {
  391. sys_name = "Mega CD";
  392. if ((Pico.m.hardware & 0xc0) == 0x80)
  393. sys_name = "Sega CD";
  394. } else if (PicoAHW & PAHW_32X) {
  395. sys_name = "32X";
  396. } else {
  397. sys_name = "MegaDrive";
  398. if ((Pico.m.hardware & 0xc0) == 0x80)
  399. sys_name = "Genesis";
  400. }
  401. tv_standard = Pico.m.pal ? "PAL" : "NTSC";
  402. fps = Pico.m.pal ? 50 : 60;
  403. emu_status_msg("%s %s / %dFPS%s", tv_standard, sys_name, fps, extra);
  404. }
  405. // XXX: portions of this code should move to pico/
  406. int emu_reload_rom(const char *rom_fname_in)
  407. {
  408. unsigned int rom_size = 0;
  409. const char *used_rom_name = NULL;
  410. char *rom_fname = NULL;
  411. unsigned char *rom_data = NULL;
  412. char ext[5];
  413. pm_file *rom = NULL;
  414. int cd_state = CIT_NOT_CD;
  415. int ret, media_type, cd_region;
  416. int cfg_loaded = 0, bad_rom = 0;
  417. int menu_romload_started = 0;
  418. int retval = 0;
  419. lprintf("emu_ReloadRom(%s)\n", rom_fname_in);
  420. rom_fname = strdup(rom_fname_in);
  421. if (rom_fname == NULL)
  422. return 0;
  423. used_rom_name = rom_fname;
  424. get_ext(rom_fname, ext);
  425. // early cleanup
  426. PicoPatchUnload();
  427. if (movie_data) {
  428. free(movie_data);
  429. movie_data = 0;
  430. }
  431. if (!strcmp(ext, ".gmv"))
  432. {
  433. // check for both gmv and rom
  434. int dummy;
  435. FILE *movie_file = fopen(rom_fname, "rb");
  436. if (!movie_file) {
  437. menu_update_msg("Failed to open movie.");
  438. goto out;
  439. }
  440. fseek(movie_file, 0, SEEK_END);
  441. movie_size = ftell(movie_file);
  442. fseek(movie_file, 0, SEEK_SET);
  443. if (movie_size < 64+3) {
  444. menu_update_msg("Invalid GMV file.");
  445. fclose(movie_file);
  446. goto out;
  447. }
  448. movie_data = malloc(movie_size);
  449. if (movie_data == NULL) {
  450. menu_update_msg("low memory.");
  451. fclose(movie_file);
  452. goto out;
  453. }
  454. dummy = fread(movie_data, 1, movie_size, movie_file);
  455. fclose(movie_file);
  456. if (strncmp((char *)movie_data, "Gens Movie TEST", 15) != 0) {
  457. menu_update_msg("Invalid GMV file.");
  458. goto out;
  459. }
  460. dummy = try_rfn_cut(rom_fname) || try_rfn_cut(rom_fname);
  461. if (!dummy) {
  462. menu_update_msg("Could't find a ROM for movie.");
  463. goto out;
  464. }
  465. get_ext(rom_fname, ext);
  466. lprintf("gmv loaded for %s\n", rom_fname);
  467. }
  468. else if (!strcmp(ext, ".pat"))
  469. {
  470. int dummy;
  471. PicoPatchLoad(rom_fname);
  472. dummy = try_rfn_cut(rom_fname) || try_rfn_cut(rom_fname);
  473. if (!dummy) {
  474. menu_update_msg("Could't find a ROM to patch.");
  475. goto out;
  476. }
  477. get_ext(rom_fname, ext);
  478. }
  479. media_type = detect_media(rom_fname);
  480. if (media_type == PM_BAD) {
  481. menu_update_msg("Not a ROM/CD img selected.");
  482. goto out;
  483. }
  484. shutdown_MCD();
  485. PicoCartUnload();
  486. rom_loaded = 0;
  487. PicoAHW = 0;
  488. if (media_type == PM_CD)
  489. {
  490. // check for MegaCD image
  491. cd_state = emu_cd_check(&cd_region, rom_fname);
  492. if (cd_state >= 0 && cd_state != CIT_NOT_CD)
  493. {
  494. // valid CD image, check for BIOS..
  495. // we need to have config loaded at this point
  496. ret = emu_read_config(rom_fname, 0);
  497. if (!ret) emu_read_config(NULL, 0);
  498. cfg_loaded = 1;
  499. if (PicoRegionOverride) {
  500. cd_region = PicoRegionOverride;
  501. lprintf("override region to %s\n", cd_region != 4 ?
  502. (cd_region == 8 ? "EU" : "JAP") : "USA");
  503. }
  504. if (!find_bios(cd_region, &used_rom_name))
  505. goto out;
  506. get_ext(used_rom_name, ext);
  507. PicoAHW |= PAHW_MCD;
  508. }
  509. else {
  510. menu_update_msg("Invalid CD image");
  511. goto out;
  512. }
  513. }
  514. else if (media_type == PM_MARK3) {
  515. lprintf("detected SMS ROM\n");
  516. PicoAHW = PAHW_SMS;
  517. }
  518. rom = pm_open(used_rom_name);
  519. if (rom == NULL) {
  520. menu_update_msg("Failed to open ROM");
  521. goto out;
  522. }
  523. menu_romload_prepare(used_rom_name); // also CD load
  524. menu_romload_started = 1;
  525. used_rom_name = NULL; // uses static_buff
  526. ret = PicoCartLoad(rom, &rom_data, &rom_size, (PicoAHW & PAHW_SMS) ? 1 : 0);
  527. pm_close(rom);
  528. if (ret != 0) {
  529. if (ret == 2) menu_update_msg("Out of memory");
  530. else if (ret == 3) menu_update_msg("Read failed");
  531. else menu_update_msg("PicoCartLoad() failed.");
  532. goto out;
  533. }
  534. // detect wrong files
  535. if (strncmp((char *)rom_data, "Pico", 4) == 0)
  536. bad_rom = 1;
  537. else if (!(PicoAHW & PAHW_SMS)) {
  538. unsigned short *d = (unsigned short *)(rom_data + 4);
  539. if ((((d[0] << 16) | d[1]) & 0xffffff) >= (int)rom_size) {
  540. lprintf("bad reset vector\n");
  541. bad_rom = 1;
  542. }
  543. }
  544. if (bad_rom) {
  545. menu_update_msg("Bad ROM detected.");
  546. goto out;
  547. }
  548. // load config for this ROM (do this before insert to get correct region)
  549. if (!(PicoAHW & PAHW_MCD))
  550. memcpy(id_header, rom_data + 0x100, sizeof(id_header));
  551. if (!cfg_loaded) {
  552. ret = emu_read_config(rom_fname, 0);
  553. if (!ret) emu_read_config(NULL, 0);
  554. }
  555. emu_make_path(static_buff, "carthw.cfg", sizeof(static_buff));
  556. if (PicoCartInsert(rom_data, rom_size, static_buff)) {
  557. menu_update_msg("Failed to load ROM.");
  558. goto out;
  559. }
  560. // insert CD if it was detected
  561. if (cd_state != CIT_NOT_CD) {
  562. ret = Insert_CD(rom_fname, cd_state);
  563. if (ret != 0) {
  564. PicoCartUnload();
  565. rom_data = NULL; // freed by unload
  566. menu_update_msg("Insert_CD() failed, invalid CD image?");
  567. goto out;
  568. }
  569. }
  570. menu_romload_end();
  571. menu_romload_started = 0;
  572. if (PicoPatches) {
  573. PicoPatchPrepare();
  574. PicoPatchApply();
  575. }
  576. // additional movie stuff
  577. if (movie_data)
  578. {
  579. if (movie_data[0x14] == '6')
  580. PicoOpt |= POPT_6BTN_PAD; // 6 button pad
  581. else PicoOpt &= ~POPT_6BTN_PAD;
  582. PicoOpt |= POPT_DIS_VDP_FIFO; // no VDP fifo timing
  583. if (movie_data[0xF] >= 'A') {
  584. if (movie_data[0x16] & 0x80) {
  585. PicoRegionOverride = 8;
  586. } else {
  587. PicoRegionOverride = 4;
  588. }
  589. PicoReset();
  590. // TODO: bits 6 & 5
  591. }
  592. movie_data[0x18+30] = 0;
  593. emu_status_msg("MOVIE: %s", (char *) &movie_data[0x18]);
  594. }
  595. else
  596. {
  597. system_announce();
  598. PicoOpt &= ~POPT_DIS_VDP_FIFO;
  599. }
  600. strncpy(rom_fname_loaded, rom_fname, sizeof(rom_fname_loaded)-1);
  601. rom_fname_loaded[sizeof(rom_fname_loaded)-1] = 0;
  602. rom_loaded = 1;
  603. // load SRAM for this ROM
  604. if (currentConfig.EmuOpt & EOPT_EN_SRAM)
  605. emu_save_load_game(1, 1);
  606. retval = 1;
  607. out:
  608. if (retval == 0 && rom_data)
  609. free(rom_data);
  610. if (menu_romload_started)
  611. menu_romload_end();
  612. free(rom_fname);
  613. return retval;
  614. }
  615. int emu_swap_cd(const char *fname)
  616. {
  617. cd_img_type cd_type;
  618. int ret = -1;
  619. cd_type = emu_cd_check(NULL, fname);
  620. if (cd_type != CIT_NOT_CD)
  621. ret = Insert_CD(fname, cd_type);
  622. if (ret != 0) {
  623. menu_update_msg("Load failed, invalid CD image?");
  624. return 0;
  625. }
  626. strncpy(rom_fname_loaded, fname, sizeof(rom_fname_loaded)-1);
  627. rom_fname_loaded[sizeof(rom_fname_loaded)-1] = 0;
  628. return 1;
  629. }
  630. // <base dir><end>
  631. void emu_make_path(char *buff, const char *end, int size)
  632. {
  633. int pos, end_len;
  634. end_len = strlen(end);
  635. pos = plat_get_root_dir(buff, size);
  636. strncpy(buff + pos, end, size - pos);
  637. buff[size - 1] = 0;
  638. if (pos + end_len > size - 1)
  639. lprintf("Warning: path truncated: %s\n", buff);
  640. }
  641. static void make_config_cfg(char *cfg_buff_512)
  642. {
  643. emu_make_path(cfg_buff_512, PicoConfigFile, 512-6);
  644. if (config_slot != 0)
  645. {
  646. char *p = strrchr(cfg_buff_512, '.');
  647. if (p == NULL)
  648. p = cfg_buff_512 + strlen(cfg_buff_512);
  649. sprintf(p, ".%i.cfg", config_slot);
  650. }
  651. cfg_buff_512[511] = 0;
  652. }
  653. void emu_prep_defconfig(void)
  654. {
  655. memset(&defaultConfig, 0, sizeof(defaultConfig));
  656. defaultConfig.EmuOpt = 0x9d | EOPT_RAM_TIMINGS|EOPT_EN_CD_LEDS;
  657. defaultConfig.s_PicoOpt = POPT_EN_STEREO|POPT_EN_FM|POPT_EN_PSG|POPT_EN_Z80 |
  658. POPT_EN_MCD_PCM|POPT_EN_MCD_CDDA|POPT_EN_SVP_DRC|POPT_ACC_SPRITES |
  659. POPT_EN_32X|POPT_EN_PWM;
  660. defaultConfig.s_PsndRate = 44100;
  661. defaultConfig.s_PicoRegion = 0; // auto
  662. defaultConfig.s_PicoAutoRgnOrder = 0x184; // US, EU, JP
  663. defaultConfig.s_PicoCDBuffers = 0;
  664. defaultConfig.confirm_save = EOPT_CONFIRM_SAVE;
  665. defaultConfig.Frameskip = -1; // auto
  666. defaultConfig.volume = 50;
  667. defaultConfig.gamma = 100;
  668. defaultConfig.scaling = 0;
  669. defaultConfig.turbo_rate = 15;
  670. // platform specific overrides
  671. pemu_prep_defconfig();
  672. }
  673. void emu_set_defconfig(void)
  674. {
  675. memcpy(&currentConfig, &defaultConfig, sizeof(currentConfig));
  676. PicoOpt = currentConfig.s_PicoOpt;
  677. PsndRate = currentConfig.s_PsndRate;
  678. PicoRegionOverride = currentConfig.s_PicoRegion;
  679. PicoAutoRgnOrder = currentConfig.s_PicoAutoRgnOrder;
  680. PicoCDBuffers = currentConfig.s_PicoCDBuffers;
  681. p32x_msh2_multiplier = MSH2_MULTI_DEFAULT;
  682. p32x_ssh2_multiplier = SSH2_MULTI_DEFAULT;
  683. }
  684. int emu_read_config(const char *rom_fname, int no_defaults)
  685. {
  686. char cfg[512];
  687. int ret;
  688. if (!no_defaults)
  689. emu_set_defconfig();
  690. if (rom_fname == NULL)
  691. {
  692. // global config
  693. make_config_cfg(cfg);
  694. ret = config_readsect(cfg, NULL);
  695. }
  696. else
  697. {
  698. char *sect = emu_make_rom_id(rom_fname);
  699. if (config_slot != 0)
  700. sprintf(cfg, "game.%i.cfg", config_slot);
  701. else strcpy(cfg, "game.cfg");
  702. ret = -1;
  703. if (config_havesect(cfg, sect))
  704. {
  705. // read user's config
  706. int vol = currentConfig.volume;
  707. emu_set_defconfig();
  708. ret = config_readsect(cfg, sect);
  709. currentConfig.volume = vol; // make vol global (bah)
  710. }
  711. else
  712. {
  713. // read global config, and apply game_def.cfg on top
  714. make_config_cfg(cfg);
  715. config_readsect(cfg, NULL);
  716. emu_make_path(cfg, "game_def.cfg", sizeof(cfg));
  717. ret = config_readsect(cfg, sect);
  718. }
  719. if (ret == 0)
  720. {
  721. lprintf("loaded cfg from sect \"%s\"\n", sect);
  722. }
  723. }
  724. pemu_validate_config();
  725. // some sanity checks
  726. #ifdef PSP
  727. /* TODO: mv to plat_validate_config() */
  728. if (currentConfig.CPUclock < 10 || currentConfig.CPUclock > 4096) currentConfig.CPUclock = 200;
  729. if (currentConfig.gamma < -4 || currentConfig.gamma > 16) currentConfig.gamma = 0;
  730. if (currentConfig.gamma2 < 0 || currentConfig.gamma2 > 2) currentConfig.gamma2 = 0;
  731. #endif
  732. if (currentConfig.volume < 0 || currentConfig.volume > 99)
  733. currentConfig.volume = 50;
  734. if (ret == 0)
  735. config_slot_current = config_slot;
  736. return (ret == 0);
  737. }
  738. int emu_write_config(int is_game)
  739. {
  740. char cfg[512], *game_sect = NULL;
  741. int ret, write_lrom = 0;
  742. if (!is_game)
  743. {
  744. make_config_cfg(cfg);
  745. write_lrom = 1;
  746. } else {
  747. if (config_slot != 0)
  748. sprintf(cfg, "game.%i.cfg", config_slot);
  749. else strcpy(cfg, "game.cfg");
  750. game_sect = emu_make_rom_id(rom_fname_loaded);
  751. lprintf("emu_write_config: sect \"%s\"\n", game_sect);
  752. }
  753. lprintf("emu_write_config: %s ", cfg);
  754. ret = config_writesect(cfg, game_sect);
  755. if (write_lrom) config_writelrom(cfg);
  756. #ifndef NO_SYNC
  757. sync();
  758. #endif
  759. lprintf((ret == 0) ? "(ok)\n" : "(failed)\n");
  760. if (ret == 0) config_slot_current = config_slot;
  761. return ret == 0;
  762. }
  763. /* always using built-in font */
  764. #define mk_text_out(name, type, val, topleft, step_x, step_y) \
  765. void name(int x, int y, const char *text) \
  766. { \
  767. int i, l, len = strlen(text); \
  768. type *screen = (type *)(topleft) + x * step_x + y * step_y; \
  769. \
  770. for (i = 0; i < len; i++, screen += 8 * step_x) \
  771. { \
  772. for (l = 0; l < 8; l++) \
  773. { \
  774. unsigned char fd = fontdata8x8[text[i] * 8 + l];\
  775. type *s = screen + l * step_y; \
  776. if (fd&0x80) s[step_x * 0] = val; \
  777. if (fd&0x40) s[step_x * 1] = val; \
  778. if (fd&0x20) s[step_x * 2] = val; \
  779. if (fd&0x10) s[step_x * 3] = val; \
  780. if (fd&0x08) s[step_x * 4] = val; \
  781. if (fd&0x04) s[step_x * 5] = val; \
  782. if (fd&0x02) s[step_x * 6] = val; \
  783. if (fd&0x01) s[step_x * 7] = val; \
  784. } \
  785. } \
  786. }
  787. mk_text_out(emu_text_out8, unsigned char, 0xf0, g_screen_ptr, 1, g_screen_width)
  788. mk_text_out(emu_text_out16, unsigned short, 0xffff, g_screen_ptr, 1, g_screen_width)
  789. mk_text_out(emu_text_out8_rot, unsigned char, 0xf0,
  790. (char *)g_screen_ptr + (g_screen_width - 1) * g_screen_height, -g_screen_height, 1)
  791. mk_text_out(emu_text_out16_rot, unsigned short, 0xffff,
  792. (short *)g_screen_ptr + (g_screen_width - 1) * g_screen_height, -g_screen_height, 1)
  793. #undef mk_text_out
  794. void update_movie(void)
  795. {
  796. int offs = Pico.m.frame_count*3 + 0x40;
  797. if (offs+3 > movie_size) {
  798. free(movie_data);
  799. movie_data = 0;
  800. emu_status_msg("END OF MOVIE.");
  801. lprintf("END OF MOVIE.\n");
  802. } else {
  803. // MXYZ SACB RLDU
  804. PicoPad[0] = ~movie_data[offs] & 0x8f; // ! SCBA RLDU
  805. if(!(movie_data[offs] & 0x10)) PicoPad[0] |= 0x40; // C
  806. if(!(movie_data[offs] & 0x20)) PicoPad[0] |= 0x10; // A
  807. if(!(movie_data[offs] & 0x40)) PicoPad[0] |= 0x20; // B
  808. PicoPad[1] = ~movie_data[offs+1] & 0x8f; // ! SCBA RLDU
  809. if(!(movie_data[offs+1] & 0x10)) PicoPad[1] |= 0x40; // C
  810. if(!(movie_data[offs+1] & 0x20)) PicoPad[1] |= 0x10; // A
  811. if(!(movie_data[offs+1] & 0x40)) PicoPad[1] |= 0x20; // B
  812. PicoPad[0] |= (~movie_data[offs+2] & 0x0A) << 8; // ! MZYX
  813. if(!(movie_data[offs+2] & 0x01)) PicoPad[0] |= 0x0400; // X
  814. if(!(movie_data[offs+2] & 0x04)) PicoPad[0] |= 0x0100; // Z
  815. PicoPad[1] |= (~movie_data[offs+2] & 0xA0) << 4; // ! MZYX
  816. if(!(movie_data[offs+2] & 0x10)) PicoPad[1] |= 0x0400; // X
  817. if(!(movie_data[offs+2] & 0x40)) PicoPad[1] |= 0x0100; // Z
  818. }
  819. }
  820. static int try_ropen_file(const char *fname)
  821. {
  822. FILE *f;
  823. f = fopen(fname, "rb");
  824. if (f) {
  825. fclose(f);
  826. return 1;
  827. }
  828. return 0;
  829. }
  830. char *emu_get_save_fname(int load, int is_sram, int slot)
  831. {
  832. char *saveFname = static_buff;
  833. char ext[16];
  834. if (is_sram)
  835. {
  836. strcpy(ext, (PicoAHW & PAHW_MCD) ? ".brm" : ".srm");
  837. romfname_ext(saveFname, sizeof(static_buff),
  838. (PicoAHW & PAHW_MCD) ? "brm"PATH_SEP : "srm"PATH_SEP, ext);
  839. if (!load)
  840. return saveFname;
  841. if (try_ropen_file(saveFname))
  842. return saveFname;
  843. romfname_ext(saveFname, sizeof(static_buff), NULL, ext);
  844. if (try_ropen_file(saveFname))
  845. return saveFname;
  846. }
  847. else
  848. {
  849. const char *ext_main = (currentConfig.EmuOpt & EOPT_GZIP_SAVES) ? ".mds.gz" : ".mds";
  850. const char *ext_othr = (currentConfig.EmuOpt & EOPT_GZIP_SAVES) ? ".mds" : ".mds.gz";
  851. ext[0] = 0;
  852. if (slot > 0 && slot < 10)
  853. sprintf(ext, ".%i", slot);
  854. strcat(ext, ext_main);
  855. if (!load) {
  856. romfname_ext(saveFname, sizeof(static_buff), "mds" PATH_SEP, ext);
  857. return saveFname;
  858. }
  859. else {
  860. romfname_ext(saveFname, sizeof(static_buff), "mds" PATH_SEP, ext);
  861. if (try_ropen_file(saveFname))
  862. return saveFname;
  863. romfname_ext(saveFname, sizeof(static_buff), NULL, ext);
  864. if (try_ropen_file(saveFname))
  865. return saveFname;
  866. // try the other ext
  867. ext[0] = 0;
  868. if (slot > 0 && slot < 10)
  869. sprintf(ext, ".%i", slot);
  870. strcat(ext, ext_othr);
  871. romfname_ext(saveFname, sizeof(static_buff), "mds"PATH_SEP, ext);
  872. if (try_ropen_file(saveFname))
  873. return saveFname;
  874. }
  875. }
  876. return NULL;
  877. }
  878. int emu_check_save_file(int slot, int *time)
  879. {
  880. return emu_get_save_fname(1, 0, slot) ? 1 : 0;
  881. }
  882. int emu_save_load_game(int load, int sram)
  883. {
  884. int ret = 0;
  885. char *saveFname;
  886. // make save filename
  887. saveFname = emu_get_save_fname(load, sram, state_slot);
  888. if (saveFname == NULL) {
  889. if (!sram)
  890. emu_status_msg(load ? "LOAD FAILED (missing file)" : "SAVE FAILED");
  891. return -1;
  892. }
  893. lprintf("saveLoad (%i, %i): %s\n", load, sram, saveFname);
  894. if (sram)
  895. {
  896. FILE *sramFile;
  897. int sram_size;
  898. unsigned char *sram_data;
  899. int truncate = 1;
  900. if (PicoAHW & PAHW_MCD)
  901. {
  902. if (PicoOpt & POPT_EN_MCD_RAMCART) {
  903. sram_size = 0x12000;
  904. sram_data = SRam.data;
  905. if (sram_data)
  906. memcpy32((int *)sram_data, (int *)Pico_mcd->bram, 0x2000/4);
  907. } else {
  908. sram_size = 0x2000;
  909. sram_data = Pico_mcd->bram;
  910. truncate = 0; // the .brm may contain RAM cart data after normal brm
  911. }
  912. } else {
  913. sram_size = SRam.size;
  914. sram_data = SRam.data;
  915. }
  916. if (sram_data == NULL)
  917. return 0; // SRam forcefully disabled for this game
  918. if (load)
  919. {
  920. sramFile = fopen(saveFname, "rb");
  921. if (!sramFile)
  922. return -1;
  923. ret = fread(sram_data, 1, sram_size, sramFile);
  924. ret = ret > 0 ? 0 : -1;
  925. fclose(sramFile);
  926. if ((PicoAHW & PAHW_MCD) && (PicoOpt&POPT_EN_MCD_RAMCART))
  927. memcpy32((int *)Pico_mcd->bram, (int *)sram_data, 0x2000/4);
  928. } else {
  929. // sram save needs some special processing
  930. // see if we have anything to save
  931. for (; sram_size > 0; sram_size--)
  932. if (sram_data[sram_size-1]) break;
  933. if (sram_size) {
  934. sramFile = fopen(saveFname, truncate ? "wb" : "r+b");
  935. if (!sramFile) sramFile = fopen(saveFname, "wb"); // retry
  936. if (!sramFile) return -1;
  937. ret = fwrite(sram_data, 1, sram_size, sramFile);
  938. ret = (ret != sram_size) ? -1 : 0;
  939. fclose(sramFile);
  940. #ifndef NO_SYNC
  941. sync();
  942. #endif
  943. }
  944. }
  945. return ret;
  946. }
  947. else
  948. {
  949. ret = PicoState(saveFname, !load);
  950. if (!ret) {
  951. #ifndef NO_SYNC
  952. if (!load) sync();
  953. #endif
  954. emu_status_msg(load ? "STATE LOADED" : "STATE SAVED");
  955. } else {
  956. emu_status_msg(load ? "LOAD FAILED" : "SAVE FAILED");
  957. ret = -1;
  958. }
  959. return ret;
  960. }
  961. }
  962. void emu_set_fastforward(int set_on)
  963. {
  964. static void *set_PsndOut = NULL;
  965. static int set_Frameskip, set_EmuOpt, is_on = 0;
  966. if (set_on && !is_on) {
  967. set_PsndOut = PsndOut;
  968. set_Frameskip = currentConfig.Frameskip;
  969. set_EmuOpt = currentConfig.EmuOpt;
  970. PsndOut = NULL;
  971. currentConfig.Frameskip = 8;
  972. currentConfig.EmuOpt &= ~4;
  973. currentConfig.EmuOpt |= 0x40000;
  974. is_on = 1;
  975. emu_status_msg("FAST FORWARD");
  976. }
  977. else if (!set_on && is_on) {
  978. PsndOut = set_PsndOut;
  979. currentConfig.Frameskip = set_Frameskip;
  980. currentConfig.EmuOpt = set_EmuOpt;
  981. PsndRerate(1);
  982. is_on = 0;
  983. }
  984. }
  985. static void emu_tray_open(void)
  986. {
  987. engineState = PGS_TrayMenu;
  988. }
  989. static void emu_tray_close(void)
  990. {
  991. emu_status_msg("CD tray closed.");
  992. }
  993. void emu_32x_startup(void)
  994. {
  995. plat_video_toggle_renderer(0, 0); // HACK
  996. system_announce();
  997. // force mode change event
  998. rendstatus_old = -1;
  999. }
  1000. void emu_reset_game(void)
  1001. {
  1002. PicoReset();
  1003. reset_timing = 1;
  1004. }
  1005. void run_events_pico(unsigned int events)
  1006. {
  1007. int lim_x;
  1008. if (events & PEV_PICO_SWINP) {
  1009. pico_inp_mode++;
  1010. if (pico_inp_mode > 2)
  1011. pico_inp_mode = 0;
  1012. switch (pico_inp_mode) {
  1013. case 2: emu_status_msg("Input: Pen on Pad"); break;
  1014. case 1: emu_status_msg("Input: Pen on Storyware"); break;
  1015. case 0: emu_status_msg("Input: Joystick");
  1016. PicoPicohw.pen_pos[0] = PicoPicohw.pen_pos[1] = 0x8000;
  1017. break;
  1018. }
  1019. }
  1020. if (events & PEV_PICO_PPREV) {
  1021. PicoPicohw.page--;
  1022. if (PicoPicohw.page < 0)
  1023. PicoPicohw.page = 0;
  1024. emu_status_msg("Page %i", PicoPicohw.page);
  1025. }
  1026. if (events & PEV_PICO_PNEXT) {
  1027. PicoPicohw.page++;
  1028. if (PicoPicohw.page > 6)
  1029. PicoPicohw.page = 6;
  1030. emu_status_msg("Page %i", PicoPicohw.page);
  1031. }
  1032. if (pico_inp_mode == 0)
  1033. return;
  1034. /* handle other input modes */
  1035. if (PicoPad[0] & 1) pico_pen_y--;
  1036. if (PicoPad[0] & 2) pico_pen_y++;
  1037. if (PicoPad[0] & 4) pico_pen_x--;
  1038. if (PicoPad[0] & 8) pico_pen_x++;
  1039. PicoPad[0] &= ~0x0f; // release UDLR
  1040. lim_x = (Pico.video.reg[12]&1) ? 319 : 255;
  1041. if (pico_pen_y < 8)
  1042. pico_pen_y = 8;
  1043. if (pico_pen_y > 224 - PICO_PEN_ADJUST_Y)
  1044. pico_pen_y = 224 - PICO_PEN_ADJUST_Y;
  1045. if (pico_pen_x < 0)
  1046. pico_pen_x = 0;
  1047. if (pico_pen_x > lim_x - PICO_PEN_ADJUST_X)
  1048. pico_pen_x = lim_x - PICO_PEN_ADJUST_X;
  1049. PicoPicohw.pen_pos[0] = pico_pen_x;
  1050. if (!(Pico.video.reg[12] & 1))
  1051. PicoPicohw.pen_pos[0] += pico_pen_x / 4;
  1052. PicoPicohw.pen_pos[0] += 0x3c;
  1053. PicoPicohw.pen_pos[1] = pico_inp_mode == 1 ? (0x2f8 + pico_pen_y) : (0x1fc + pico_pen_y);
  1054. }
  1055. static void do_turbo(int *pad, int acts)
  1056. {
  1057. static int turbo_pad = 0;
  1058. static unsigned char turbo_cnt[3] = { 0, 0, 0 };
  1059. int inc = currentConfig.turbo_rate * 2;
  1060. if (acts & 0x1000) {
  1061. turbo_cnt[0] += inc;
  1062. if (turbo_cnt[0] >= 60)
  1063. turbo_pad ^= 0x10, turbo_cnt[0] = 0;
  1064. }
  1065. if (acts & 0x2000) {
  1066. turbo_cnt[1] += inc;
  1067. if (turbo_cnt[1] >= 60)
  1068. turbo_pad ^= 0x20, turbo_cnt[1] = 0;
  1069. }
  1070. if (acts & 0x4000) {
  1071. turbo_cnt[2] += inc;
  1072. if (turbo_cnt[2] >= 60)
  1073. turbo_pad ^= 0x40, turbo_cnt[2] = 0;
  1074. }
  1075. *pad |= turbo_pad & (acts >> 8);
  1076. }
  1077. static void run_events_ui(unsigned int which)
  1078. {
  1079. if (which & (PEV_STATE_LOAD|PEV_STATE_SAVE))
  1080. {
  1081. int do_it = 1;
  1082. if ( emu_check_save_file(state_slot, NULL) &&
  1083. (((which & PEV_STATE_LOAD) && (currentConfig.confirm_save & EOPT_CONFIRM_LOAD)) ||
  1084. ((which & PEV_STATE_SAVE) && (currentConfig.confirm_save & EOPT_CONFIRM_SAVE))) )
  1085. {
  1086. const char *nm;
  1087. char tmp[64];
  1088. int keys, len;
  1089. strcpy(tmp, (which & PEV_STATE_LOAD) ? "LOAD STATE?" : "OVERWRITE SAVE?");
  1090. len = strlen(tmp);
  1091. nm = in_get_key_name(-1, -PBTN_MA3);
  1092. snprintf(tmp + len, sizeof(tmp) - len, "(%s=yes, ", nm);
  1093. len = strlen(tmp);
  1094. nm = in_get_key_name(-1, -PBTN_MBACK);
  1095. snprintf(tmp + len, sizeof(tmp) - len, "%s=no)", nm);
  1096. plat_status_msg_busy_first(tmp);
  1097. in_set_config_int(0, IN_CFG_BLOCKING, 1);
  1098. while (in_menu_wait_any(NULL, 50) & (PBTN_MA3|PBTN_MBACK))
  1099. ;
  1100. while ( !((keys = in_menu_wait_any(NULL, 50)) & (PBTN_MA3|PBTN_MBACK)) )
  1101. ;
  1102. if (keys & PBTN_MBACK)
  1103. do_it = 0;
  1104. while (in_menu_wait_any(NULL, 50) & (PBTN_MA3|PBTN_MBACK))
  1105. ;
  1106. in_set_config_int(0, IN_CFG_BLOCKING, 0);
  1107. }
  1108. if (do_it) {
  1109. plat_status_msg_busy_first((which & PEV_STATE_LOAD) ? "LOADING STATE" : "SAVING STATE");
  1110. PicoStateProgressCB = plat_status_msg_busy_next;
  1111. emu_save_load_game((which & PEV_STATE_LOAD) ? 1 : 0, 0);
  1112. PicoStateProgressCB = NULL;
  1113. }
  1114. }
  1115. if (which & PEV_SWITCH_RND)
  1116. {
  1117. plat_video_toggle_renderer(1, 0);
  1118. }
  1119. if (which & (PEV_SSLOT_PREV|PEV_SSLOT_NEXT))
  1120. {
  1121. if (which & PEV_SSLOT_PREV) {
  1122. state_slot -= 1;
  1123. if (state_slot < 0)
  1124. state_slot = 9;
  1125. } else {
  1126. state_slot += 1;
  1127. if (state_slot > 9)
  1128. state_slot = 0;
  1129. }
  1130. emu_status_msg("SAVE SLOT %i [%s]", state_slot,
  1131. emu_check_save_file(state_slot, NULL) ? "USED" : "FREE");
  1132. }
  1133. if (which & PEV_MENU)
  1134. engineState = PGS_Menu;
  1135. }
  1136. void emu_update_input(void)
  1137. {
  1138. static int prev_events = 0;
  1139. int actions[IN_BINDTYPE_COUNT] = { 0, };
  1140. int pl_actions[2];
  1141. int events;
  1142. in_update(actions);
  1143. pl_actions[0] = actions[IN_BINDTYPE_PLAYER12];
  1144. pl_actions[1] = actions[IN_BINDTYPE_PLAYER12] >> 16;
  1145. PicoPad[0] = pl_actions[0] & 0xfff;
  1146. PicoPad[1] = pl_actions[1] & 0xfff;
  1147. if (pl_actions[0] & 0x7000)
  1148. do_turbo(&PicoPad[0], pl_actions[0]);
  1149. if (pl_actions[1] & 0x7000)
  1150. do_turbo(&PicoPad[1], pl_actions[1]);
  1151. events = actions[IN_BINDTYPE_EMU] & PEV_MASK;
  1152. // volume is treated in special way and triggered every frame
  1153. if (events & (PEV_VOL_DOWN|PEV_VOL_UP))
  1154. plat_update_volume(1, events & PEV_VOL_UP);
  1155. if ((events ^ prev_events) & PEV_FF) {
  1156. emu_set_fastforward(events & PEV_FF);
  1157. plat_update_volume(0, 0);
  1158. reset_timing = 1;
  1159. }
  1160. events &= ~prev_events;
  1161. if (PicoAHW == PAHW_PICO)
  1162. run_events_pico(events);
  1163. if (events)
  1164. run_events_ui(events);
  1165. if (movie_data)
  1166. update_movie();
  1167. prev_events = actions[IN_BINDTYPE_EMU] & PEV_MASK;
  1168. }
  1169. static void mkdir_path(char *path_with_reserve, int pos, const char *name)
  1170. {
  1171. strcpy(path_with_reserve + pos, name);
  1172. if (plat_is_dir(path_with_reserve))
  1173. return;
  1174. if (mkdir(path_with_reserve, 0777) < 0)
  1175. lprintf("failed to create: %s\n", path_with_reserve);
  1176. }
  1177. void emu_cmn_forced_frame(int no_scale, int do_emu)
  1178. {
  1179. int po_old = PicoOpt;
  1180. memset32(g_screen_ptr, 0, g_screen_width * g_screen_height * 2 / 4);
  1181. PicoOpt &= ~POPT_ALT_RENDERER;
  1182. PicoOpt |= POPT_ACC_SPRITES;
  1183. if (!no_scale)
  1184. PicoOpt |= POPT_EN_SOFTSCALE;
  1185. PicoDrawSetOutFormat(PDF_RGB555, 1);
  1186. Pico.m.dirtyPal = 1;
  1187. if (do_emu)
  1188. PicoFrame();
  1189. else
  1190. PicoFrameDrawOnly();
  1191. PicoOpt = po_old;
  1192. }
  1193. void emu_init(void)
  1194. {
  1195. char path[512];
  1196. int pos;
  1197. #if 0
  1198. // FIXME: handle through menu, etc
  1199. FILE *f;
  1200. f = fopen("32X_M_BIOS.BIN", "rb");
  1201. p32x_bios_m = malloc(2048);
  1202. fread(p32x_bios_m, 1, 2048, f);
  1203. fclose(f);
  1204. f = fopen("32X_S_BIOS.BIN", "rb");
  1205. p32x_bios_s = malloc(1024);
  1206. fread(p32x_bios_s, 1, 1024, f);
  1207. fclose(f);
  1208. #endif
  1209. /* make dirs for saves */
  1210. pos = plat_get_root_dir(path, sizeof(path) - 4);
  1211. mkdir_path(path, pos, "mds");
  1212. mkdir_path(path, pos, "srm");
  1213. mkdir_path(path, pos, "brm");
  1214. pprof_init();
  1215. make_config_cfg(path);
  1216. config_readlrom(path);
  1217. PicoInit();
  1218. PicoMessage = plat_status_msg_busy_next;
  1219. PicoMCDopenTray = emu_tray_open;
  1220. PicoMCDcloseTray = emu_tray_close;
  1221. sndout_init();
  1222. }
  1223. void emu_finish(void)
  1224. {
  1225. // save SRAM
  1226. if ((currentConfig.EmuOpt & EOPT_EN_SRAM) && SRam.changed) {
  1227. emu_save_load_game(0, 1);
  1228. SRam.changed = 0;
  1229. }
  1230. if (!(currentConfig.EmuOpt & EOPT_NO_AUTOSVCFG)) {
  1231. char cfg[512];
  1232. make_config_cfg(cfg);
  1233. config_writelrom(cfg);
  1234. #ifndef NO_SYNC
  1235. sync();
  1236. #endif
  1237. }
  1238. pprof_finish();
  1239. PicoExit();
  1240. sndout_exit();
  1241. }
  1242. static void snd_write_nonblocking(int len)
  1243. {
  1244. sndout_write_nb(PsndOut, len);
  1245. }
  1246. void emu_sound_start(void)
  1247. {
  1248. PsndOut = NULL;
  1249. if (currentConfig.EmuOpt & EOPT_EN_SOUND)
  1250. {
  1251. int is_stereo = (PicoOpt & POPT_EN_STEREO) ? 1 : 0;
  1252. PsndRerate(Pico.m.frame_count ? 1 : 0);
  1253. printf("starting audio: %i len: %i stereo: %i, pal: %i\n",
  1254. PsndRate, PsndLen, is_stereo, Pico.m.pal);
  1255. sndout_start(PsndRate, is_stereo);
  1256. PicoWriteSound = snd_write_nonblocking;
  1257. plat_update_volume(0, 0);
  1258. memset(sndBuffer, 0, sizeof(sndBuffer));
  1259. PsndOut = sndBuffer;
  1260. }
  1261. }
  1262. void emu_sound_stop(void)
  1263. {
  1264. sndout_stop();
  1265. }
  1266. void emu_sound_wait(void)
  1267. {
  1268. sndout_wait();
  1269. }
  1270. static void emu_loop_prep(void)
  1271. {
  1272. static int pal_old = -1;
  1273. static int filter_old = -1;
  1274. if (currentConfig.CPUclock != plat_target_cpu_clock_get())
  1275. plat_target_cpu_clock_set(currentConfig.CPUclock);
  1276. if (Pico.m.pal != pal_old) {
  1277. plat_target_lcdrate_set(Pico.m.pal);
  1278. pal_old = Pico.m.pal;
  1279. }
  1280. if (currentConfig.filter != filter_old) {
  1281. plat_target_hwfilter_set(currentConfig.filter);
  1282. filter_old = currentConfig.filter;
  1283. }
  1284. plat_target_gamma_set(currentConfig.gamma, 0);
  1285. pemu_loop_prep();
  1286. }
  1287. static void skip_frame(int do_audio)
  1288. {
  1289. PicoSkipFrame = do_audio ? 1 : 2;
  1290. PicoFrame();
  1291. PicoSkipFrame = 0;
  1292. }
  1293. /* our tick here is 1 us right now */
  1294. #define ms_to_ticks(x) (unsigned int)(x * 1000)
  1295. #define get_ticks() plat_get_ticks_us()
  1296. void emu_loop(void)
  1297. {
  1298. int pframes_done; /* "period" frames, used for sync */
  1299. int frames_done, frames_shown; /* actual frames for fps counter */
  1300. int target_fps, target_frametime;
  1301. unsigned int timestamp_base = 0, timestamp_fps;
  1302. char *notice_msg = NULL;
  1303. char fpsbuff[24];
  1304. int i;
  1305. fpsbuff[0] = 0;
  1306. /* make sure we are in correct mode */
  1307. Pico.m.dirtyPal = 1;
  1308. rendstatus_old = -1;
  1309. PicoLoopPrepare();
  1310. // prepare CD buffer
  1311. if (PicoAHW & PAHW_MCD)
  1312. PicoCDBufferInit();
  1313. plat_video_loop_prepare();
  1314. emu_loop_prep();
  1315. pemu_sound_start();
  1316. /* number of ticks per frame */
  1317. if (Pico.m.pal) {
  1318. target_fps = 50;
  1319. target_frametime = ms_to_ticks(1000) / 50;
  1320. } else {
  1321. target_fps = 60;
  1322. target_frametime = ms_to_ticks(1000) / 60 + 1;
  1323. }
  1324. timestamp_fps = get_ticks();
  1325. reset_timing = 1;
  1326. frames_done = frames_shown = pframes_done = 0;
  1327. plat_video_wait_vsync();
  1328. /* loop with resync every 1 sec. */
  1329. while (engineState == PGS_Running)
  1330. {
  1331. unsigned int timestamp;
  1332. int diff, diff_lim;
  1333. pprof_start(main);
  1334. timestamp = get_ticks();
  1335. if (reset_timing) {
  1336. reset_timing = 0;
  1337. timestamp_base = timestamp;
  1338. pframes_done = 0;
  1339. }
  1340. // show notice_msg message?
  1341. if (notice_msg_time != 0)
  1342. {
  1343. static int noticeMsgSum;
  1344. if (timestamp - ms_to_ticks(notice_msg_time) > ms_to_ticks(STATUS_MSG_TIMEOUT)) {
  1345. notice_msg_time = 0;
  1346. plat_status_msg_clear();
  1347. notice_msg = NULL;
  1348. } else {
  1349. int sum = noticeMsg[0] + noticeMsg[1] + noticeMsg[2];
  1350. if (sum != noticeMsgSum) {
  1351. plat_status_msg_clear();
  1352. noticeMsgSum = sum;
  1353. }
  1354. notice_msg = noticeMsg;
  1355. }
  1356. }
  1357. // second changed?
  1358. if (timestamp - timestamp_fps >= ms_to_ticks(1000))
  1359. {
  1360. #ifdef BENCHMARK
  1361. static int bench = 0, bench_fps = 0, bench_fps_s = 0, bfp = 0, bf[4];
  1362. if (++bench == 10) {
  1363. bench = 0;
  1364. bench_fps_s = bench_fps;
  1365. bf[bfp++ & 3] = bench_fps;
  1366. bench_fps = 0;
  1367. }
  1368. bench_fps += frames_shown;
  1369. sprintf(fpsbuff, "%02i/%02i/%02i", frames_shown, bench_fps_s, (bf[0]+bf[1]+bf[2]+bf[3])>>2);
  1370. printf("%s\n", fpsbuff);
  1371. #else
  1372. if (currentConfig.EmuOpt & EOPT_SHOW_FPS) {
  1373. sprintf(fpsbuff, "%02i/%02i", frames_shown, frames_done);
  1374. if (fpsbuff[5] == 0) { fpsbuff[5] = fpsbuff[6] = ' '; fpsbuff[7] = 0; }
  1375. }
  1376. #endif
  1377. frames_shown = frames_done = 0;
  1378. timestamp_fps += ms_to_ticks(1000);
  1379. }
  1380. #ifdef PFRAMES
  1381. sprintf(fpsbuff, "%i", Pico.m.frame_count);
  1382. #endif
  1383. if (timestamp - timestamp_base >= ms_to_ticks(1000))
  1384. {
  1385. if ((currentConfig.EmuOpt & EOPT_NO_FRMLIMIT) && currentConfig.Frameskip >= 0)
  1386. pframes_done = 0;
  1387. else
  1388. pframes_done -= target_fps;
  1389. if (pframes_done < -2) {
  1390. /* don't drag more than 2 frames behind */
  1391. pframes_done = -2;
  1392. timestamp_base = timestamp - 2 * target_frametime;
  1393. }
  1394. else
  1395. timestamp_base += ms_to_ticks(1000);
  1396. }
  1397. diff = timestamp - timestamp_base;
  1398. diff_lim = (pframes_done + 1) * target_frametime;
  1399. if (currentConfig.Frameskip >= 0) // frameskip enabled
  1400. {
  1401. for (i = 0; i < currentConfig.Frameskip; i++) {
  1402. emu_update_input();
  1403. skip_frame(1);
  1404. pframes_done++; frames_done++;
  1405. diff_lim += target_frametime;
  1406. if (!(currentConfig.EmuOpt & (EOPT_NO_FRMLIMIT|EOPT_EXT_FRMLIMIT))) {
  1407. timestamp = get_ticks();
  1408. diff = timestamp - timestamp_base;
  1409. if (!reset_timing && diff < diff_lim) // we are too fast
  1410. plat_wait_till_us(timestamp_base + diff_lim);
  1411. }
  1412. }
  1413. }
  1414. else if (diff > diff_lim)
  1415. {
  1416. /* no time left for this frame - skip */
  1417. /* limit auto frameskip to 8 */
  1418. if (frames_done / 8 <= frames_shown) {
  1419. emu_update_input();
  1420. skip_frame(diff < diff_lim + target_frametime * 16);
  1421. pframes_done++; frames_done++;
  1422. continue;
  1423. }
  1424. }
  1425. emu_update_input();
  1426. PicoFrame();
  1427. pemu_finalize_frame(fpsbuff, notice_msg);
  1428. // plat_video_flip();
  1429. /* frame limiter */
  1430. if (!reset_timing && !(currentConfig.EmuOpt & (EOPT_NO_FRMLIMIT|EOPT_EXT_FRMLIMIT)))
  1431. {
  1432. timestamp = get_ticks();
  1433. diff = timestamp - timestamp_base;
  1434. // sleep or vsync if we are still too fast
  1435. if (diff < diff_lim)
  1436. {
  1437. // we are too fast
  1438. plat_wait_till_us(timestamp_base + diff_lim - target_frametime / 4);
  1439. if (currentConfig.EmuOpt & EOPT_VSYNC)
  1440. plat_video_wait_vsync();
  1441. }
  1442. }
  1443. // XXX: for some plats it might be better to flip before vsync
  1444. // (due to shadow registers in display hw)
  1445. plat_video_flip();
  1446. pframes_done++; frames_done++; frames_shown++;
  1447. pprof_end(main);
  1448. }
  1449. emu_set_fastforward(0);
  1450. // save SRAM
  1451. if ((currentConfig.EmuOpt & EOPT_EN_SRAM) && SRam.changed) {
  1452. plat_status_msg_busy_first("Writing SRAM/BRAM...");
  1453. emu_save_load_game(0, 1);
  1454. SRam.changed = 0;
  1455. }
  1456. pemu_loop_end();
  1457. emu_sound_stop();
  1458. // pemu_loop_end() might want to do 1 frame for bg image,
  1459. // so free CD buffer here
  1460. if (PicoAHW & PAHW_MCD)
  1461. PicoCDBufferFree();
  1462. }