libretro.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904
  1. /*
  2. * libretro core glue for PicoDrive
  3. * (C) notaz, 2013
  4. *
  5. * This work is licensed under the terms of MAME license.
  6. * See COPYING file in the top-level directory.
  7. */
  8. #define _GNU_SOURCE 1 // mremap
  9. #include <stdio.h>
  10. #include <stdarg.h>
  11. #include <string.h>
  12. #ifndef _WIN32
  13. #include <sys/mman.h>
  14. #else
  15. #include <io.h>
  16. #include <windows.h>
  17. #include <sys/types.h>
  18. #endif
  19. #include <errno.h>
  20. #ifdef __MACH__
  21. #include <libkern/OSCacheControl.h>
  22. #endif
  23. #include <pico/pico_int.h>
  24. #include <pico/state.h>
  25. #include "common/input_pico.h"
  26. #include "common/version.h"
  27. #include "libretro.h"
  28. static retro_video_refresh_t video_cb;
  29. static retro_input_poll_t input_poll_cb;
  30. static retro_input_state_t input_state_cb;
  31. static retro_environment_t environ_cb;
  32. static retro_audio_sample_batch_t audio_batch_cb;
  33. static FILE *emu_log;
  34. #define VOUT_MAX_WIDTH 320
  35. #define VOUT_MAX_HEIGHT 240
  36. static void *vout_buf;
  37. static int vout_width, vout_height, vout_offset;
  38. static short __attribute__((aligned(4))) sndBuffer[2*44100/50];
  39. static void snd_write(int len);
  40. #ifdef _WIN32
  41. #define SLASH '\\'
  42. #else
  43. #define SLASH '/'
  44. #endif
  45. /* functions called by the core */
  46. void cache_flush_d_inval_i(void *start, void *end)
  47. {
  48. #ifdef __arm__
  49. #if defined(__BLACKBERRY_QNX__)
  50. msync(start, end - start, MS_SYNC | MS_CACHE_ONLY | MS_INVALIDATE_ICACHE);
  51. #elif defined(__MACH__)
  52. size_t len = (char *)end - (char *)start;
  53. sys_dcache_flush(start, len);
  54. sys_icache_invalidate(start, len);
  55. #else
  56. __clear_cache(start, end);
  57. #endif
  58. #endif
  59. }
  60. #ifdef _WIN32
  61. /* mmap() replacement for Windows
  62. *
  63. * Author: Mike Frysinger <vapier@gentoo.org>
  64. * Placed into the public domain
  65. */
  66. /* References:
  67. * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx
  68. * CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx
  69. * MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx
  70. * UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx
  71. */
  72. #define PROT_READ 0x1
  73. #define PROT_WRITE 0x2
  74. /* This flag is only available in WinXP+ */
  75. #ifdef FILE_MAP_EXECUTE
  76. #define PROT_EXEC 0x4
  77. #else
  78. #define PROT_EXEC 0x0
  79. #define FILE_MAP_EXECUTE 0
  80. #endif
  81. #define MAP_SHARED 0x01
  82. #define MAP_PRIVATE 0x02
  83. #define MAP_ANONYMOUS 0x20
  84. #define MAP_ANON MAP_ANONYMOUS
  85. #define MAP_FAILED ((void *) -1)
  86. #ifdef __USE_FILE_OFFSET64
  87. # define DWORD_HI(x) (x >> 32)
  88. # define DWORD_LO(x) ((x) & 0xffffffff)
  89. #else
  90. # define DWORD_HI(x) (0)
  91. # define DWORD_LO(x) (x)
  92. #endif
  93. static void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
  94. {
  95. if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
  96. return MAP_FAILED;
  97. if (fd == -1) {
  98. if (!(flags & MAP_ANON) || offset)
  99. return MAP_FAILED;
  100. } else if (flags & MAP_ANON)
  101. return MAP_FAILED;
  102. DWORD flProtect;
  103. if (prot & PROT_WRITE) {
  104. if (prot & PROT_EXEC)
  105. flProtect = PAGE_EXECUTE_READWRITE;
  106. else
  107. flProtect = PAGE_READWRITE;
  108. } else if (prot & PROT_EXEC) {
  109. if (prot & PROT_READ)
  110. flProtect = PAGE_EXECUTE_READ;
  111. else if (prot & PROT_EXEC)
  112. flProtect = PAGE_EXECUTE;
  113. } else
  114. flProtect = PAGE_READONLY;
  115. off_t end = length + offset;
  116. HANDLE mmap_fd, h;
  117. if (fd == -1)
  118. mmap_fd = INVALID_HANDLE_VALUE;
  119. else
  120. mmap_fd = (HANDLE)_get_osfhandle(fd);
  121. h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL);
  122. if (h == NULL)
  123. return MAP_FAILED;
  124. DWORD dwDesiredAccess;
  125. if (prot & PROT_WRITE)
  126. dwDesiredAccess = FILE_MAP_WRITE;
  127. else
  128. dwDesiredAccess = FILE_MAP_READ;
  129. if (prot & PROT_EXEC)
  130. dwDesiredAccess |= FILE_MAP_EXECUTE;
  131. if (flags & MAP_PRIVATE)
  132. dwDesiredAccess |= FILE_MAP_COPY;
  133. void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length);
  134. if (ret == NULL) {
  135. CloseHandle(h);
  136. ret = MAP_FAILED;
  137. }
  138. return ret;
  139. }
  140. static void munmap(void *addr, size_t length)
  141. {
  142. UnmapViewOfFile(addr);
  143. /* ruh-ro, we leaked handle from CreateFileMapping() ... */
  144. }
  145. #endif
  146. #ifndef MAP_ANONYMOUS
  147. #define MAP_ANONYMOUS MAP_ANON
  148. #endif
  149. void *plat_mmap(unsigned long addr, size_t size, int need_exec, int is_fixed)
  150. {
  151. int flags = MAP_PRIVATE | MAP_ANONYMOUS;
  152. void *req, *ret;
  153. req = (void *)addr;
  154. ret = mmap(req, size, PROT_READ | PROT_WRITE, flags, -1, 0);
  155. if (ret == MAP_FAILED) {
  156. lprintf("mmap(%08lx, %zd) failed: %d\n", addr, size, errno);
  157. return NULL;
  158. }
  159. if (addr != 0 && ret != (void *)addr) {
  160. lprintf("warning: wanted to map @%08lx, got %p\n",
  161. addr, ret);
  162. if (is_fixed) {
  163. munmap(ret, size);
  164. return NULL;
  165. }
  166. }
  167. return ret;
  168. }
  169. void *plat_mremap(void *ptr, size_t oldsize, size_t newsize)
  170. {
  171. #ifdef __linux__
  172. void *ret = mremap(ptr, oldsize, newsize, 0);
  173. if (ret == MAP_FAILED)
  174. return NULL;
  175. return ret;
  176. #else
  177. void *tmp, *ret;
  178. size_t preserve_size;
  179. preserve_size = oldsize;
  180. if (preserve_size > newsize)
  181. preserve_size = newsize;
  182. tmp = malloc(preserve_size);
  183. if (tmp == NULL)
  184. return NULL;
  185. memcpy(tmp, ptr, preserve_size);
  186. munmap(ptr, oldsize);
  187. ret = mmap(ptr, newsize, PROT_READ | PROT_WRITE,
  188. MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  189. if (ret == MAP_FAILED) {
  190. free(tmp);
  191. return NULL;
  192. }
  193. memcpy(ret, tmp, preserve_size);
  194. free(tmp);
  195. return ret;
  196. #endif
  197. }
  198. void plat_munmap(void *ptr, size_t size)
  199. {
  200. if (ptr != NULL)
  201. munmap(ptr, size);
  202. }
  203. int plat_mem_set_exec(void *ptr, size_t size)
  204. {
  205. #ifdef _WIN32
  206. int ret = VirtualProtect(ptr,size,PAGE_EXECUTE_READWRITE,0);
  207. if (ret == 0)
  208. lprintf("mprotect(%p, %zd) failed: %d\n", ptr, size, 0);
  209. #else
  210. int ret = mprotect(ptr, size, PROT_READ | PROT_WRITE | PROT_EXEC);
  211. if (ret != 0)
  212. lprintf("mprotect(%p, %zd) failed: %d\n", ptr, size, errno);
  213. #endif
  214. return ret;
  215. }
  216. void emu_video_mode_change(int start_line, int line_count, int is_32cols)
  217. {
  218. memset(vout_buf, 0, 320 * 240 * 2);
  219. vout_width = is_32cols ? 256 : 320;
  220. PicoDrawSetOutBuf(vout_buf, vout_width * 2);
  221. vout_height = line_count;
  222. vout_offset = vout_width * start_line;
  223. }
  224. void emu_32x_startup(void)
  225. {
  226. }
  227. #ifndef ANDROID
  228. void lprintf(const char *fmt, ...)
  229. {
  230. va_list list;
  231. va_start(list, fmt);
  232. fprintf(emu_log, "PicoDrive: ");
  233. vfprintf(emu_log, fmt, list);
  234. va_end(list);
  235. fflush(emu_log);
  236. }
  237. #else
  238. #include <android/log.h>
  239. void lprintf(const char *fmt, ...)
  240. {
  241. va_list list;
  242. va_start(list, fmt);
  243. __android_log_vprint(ANDROID_LOG_INFO, "PicoDrive", fmt, list);
  244. va_end(list);
  245. }
  246. #endif
  247. /* libretro */
  248. void retro_set_environment(retro_environment_t cb)
  249. {
  250. static const struct retro_variable vars[] = {
  251. //{ "region", "Region; Auto|NTSC|PAL" },
  252. { "picodrive_input1", "Input device 1; 3 button pad|6 button pad|None" },
  253. { "picodrive_input2", "Input device 2; 3 button pad|6 button pad|None" },
  254. { "picodrive_sprlim", "No sprite limit; disabled|enabled" },
  255. { "picodrive_ramcart", "MegaCD RAM cart; disabled|enabled" },
  256. #ifdef DRC_SH2
  257. { "picodrive_drc", "Dynamic recompilers; enabled|disabled" },
  258. #endif
  259. { NULL, NULL },
  260. };
  261. environ_cb = cb;
  262. cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)vars);
  263. }
  264. void retro_set_video_refresh(retro_video_refresh_t cb) { video_cb = cb; }
  265. void retro_set_audio_sample(retro_audio_sample_t cb) { (void)cb; }
  266. void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) { audio_batch_cb = cb; }
  267. void retro_set_input_poll(retro_input_poll_t cb) { input_poll_cb = cb; }
  268. void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; }
  269. unsigned retro_api_version(void)
  270. {
  271. return RETRO_API_VERSION;
  272. }
  273. void retro_set_controller_port_device(unsigned port, unsigned device)
  274. {
  275. }
  276. void retro_get_system_info(struct retro_system_info *info)
  277. {
  278. memset(info, 0, sizeof(*info));
  279. info->library_name = "PicoDrive";
  280. info->library_version = VERSION;
  281. info->valid_extensions = "bin|gen|smd|md|32x|cue|iso|sms";
  282. info->need_fullpath = true;
  283. }
  284. void retro_get_system_av_info(struct retro_system_av_info *info)
  285. {
  286. memset(info, 0, sizeof(*info));
  287. info->timing.fps = Pico.m.pal ? 50 : 60;
  288. info->timing.sample_rate = 44100;
  289. info->geometry.base_width = 320;
  290. info->geometry.base_height = vout_height;
  291. info->geometry.max_width = VOUT_MAX_WIDTH;
  292. info->geometry.max_height = VOUT_MAX_HEIGHT;
  293. info->geometry.aspect_ratio = 0.0f;
  294. }
  295. /* savestates */
  296. struct savestate_state {
  297. const char *load_buf;
  298. char *save_buf;
  299. size_t size;
  300. size_t pos;
  301. };
  302. size_t state_read(void *p, size_t size, size_t nmemb, void *file)
  303. {
  304. struct savestate_state *state = file;
  305. size_t bsize = size * nmemb;
  306. if (state->pos + bsize > state->size) {
  307. lprintf("savestate error: %u/%u\n",
  308. state->pos + bsize, state->size);
  309. bsize = state->size - state->pos;
  310. if ((int)bsize <= 0)
  311. return 0;
  312. }
  313. memcpy(p, state->load_buf + state->pos, bsize);
  314. state->pos += bsize;
  315. return bsize;
  316. }
  317. size_t state_write(void *p, size_t size, size_t nmemb, void *file)
  318. {
  319. struct savestate_state *state = file;
  320. size_t bsize = size * nmemb;
  321. if (state->pos + bsize > state->size) {
  322. lprintf("savestate error: %u/%u\n",
  323. state->pos + bsize, state->size);
  324. bsize = state->size - state->pos;
  325. if ((int)bsize <= 0)
  326. return 0;
  327. }
  328. memcpy(state->save_buf + state->pos, p, bsize);
  329. state->pos += bsize;
  330. return bsize;
  331. }
  332. size_t state_skip(void *p, size_t size, size_t nmemb, void *file)
  333. {
  334. struct savestate_state *state = file;
  335. size_t bsize = size * nmemb;
  336. state->pos += bsize;
  337. return bsize;
  338. }
  339. size_t state_eof(void *file)
  340. {
  341. struct savestate_state *state = file;
  342. return state->pos >= state->size;
  343. }
  344. int state_fseek(void *file, long offset, int whence)
  345. {
  346. struct savestate_state *state = file;
  347. switch (whence) {
  348. case SEEK_SET:
  349. state->pos = offset;
  350. break;
  351. case SEEK_CUR:
  352. state->pos += offset;
  353. break;
  354. case SEEK_END:
  355. state->pos = state->size + offset;
  356. break;
  357. }
  358. return (int)state->pos;
  359. }
  360. /* savestate sizes vary wildly depending if cd/32x or
  361. * carthw is active, so run the whole thing to get size */
  362. size_t retro_serialize_size(void)
  363. {
  364. struct savestate_state state = { 0, };
  365. int ret;
  366. ret = PicoStateFP(&state, 1, NULL, state_skip, NULL, state_fseek);
  367. if (ret != 0)
  368. return 0;
  369. return state.pos;
  370. }
  371. bool retro_serialize(void *data, size_t size)
  372. {
  373. struct savestate_state state = { 0, };
  374. int ret;
  375. state.save_buf = data;
  376. state.size = size;
  377. state.pos = 0;
  378. ret = PicoStateFP(&state, 1, NULL, state_write,
  379. NULL, state_fseek);
  380. return ret == 0;
  381. }
  382. bool retro_unserialize(const void *data, size_t size)
  383. {
  384. struct savestate_state state = { 0, };
  385. int ret;
  386. state.load_buf = data;
  387. state.size = size;
  388. state.pos = 0;
  389. ret = PicoStateFP(&state, 0, state_read, NULL,
  390. state_eof, state_fseek);
  391. return ret == 0;
  392. }
  393. /* cheats - TODO */
  394. void retro_cheat_reset(void)
  395. {
  396. }
  397. void retro_cheat_set(unsigned index, bool enabled, const char *code)
  398. {
  399. }
  400. /* multidisk support */
  401. static bool disk_ejected;
  402. static unsigned int disk_current_index;
  403. static unsigned int disk_count;
  404. static struct disks_state {
  405. char *fname;
  406. } disks[8];
  407. static bool disk_set_eject_state(bool ejected)
  408. {
  409. // TODO?
  410. disk_ejected = ejected;
  411. return true;
  412. }
  413. static bool disk_get_eject_state(void)
  414. {
  415. return disk_ejected;
  416. }
  417. static unsigned int disk_get_image_index(void)
  418. {
  419. return disk_current_index;
  420. }
  421. static bool disk_set_image_index(unsigned int index)
  422. {
  423. enum cd_img_type cd_type;
  424. int ret;
  425. if (index >= sizeof(disks) / sizeof(disks[0]))
  426. return false;
  427. if (disks[index].fname == NULL) {
  428. lprintf("missing disk #%u\n", index);
  429. // RetroArch specifies "no disk" with index == count,
  430. // so don't fail here..
  431. disk_current_index = index;
  432. return true;
  433. }
  434. lprintf("switching to disk %u: \"%s\"\n", index,
  435. disks[index].fname);
  436. ret = -1;
  437. cd_type = PicoCdCheck(disks[index].fname, NULL);
  438. if (cd_type != CIT_NOT_CD)
  439. ret = cdd_load(disks[index].fname, cd_type);
  440. if (ret != 0) {
  441. lprintf("Load failed, invalid CD image?\n");
  442. return 0;
  443. }
  444. disk_current_index = index;
  445. return true;
  446. }
  447. static unsigned int disk_get_num_images(void)
  448. {
  449. return disk_count;
  450. }
  451. static bool disk_replace_image_index(unsigned index,
  452. const struct retro_game_info *info)
  453. {
  454. bool ret = true;
  455. if (index >= sizeof(disks) / sizeof(disks[0]))
  456. return false;
  457. if (disks[index].fname != NULL)
  458. free(disks[index].fname);
  459. disks[index].fname = NULL;
  460. if (info != NULL) {
  461. disks[index].fname = strdup(info->path);
  462. if (index == disk_current_index)
  463. ret = disk_set_image_index(index);
  464. }
  465. return ret;
  466. }
  467. static bool disk_add_image_index(void)
  468. {
  469. if (disk_count >= sizeof(disks) / sizeof(disks[0]))
  470. return false;
  471. disk_count++;
  472. return true;
  473. }
  474. static struct retro_disk_control_callback disk_control = {
  475. .set_eject_state = disk_set_eject_state,
  476. .get_eject_state = disk_get_eject_state,
  477. .get_image_index = disk_get_image_index,
  478. .set_image_index = disk_set_image_index,
  479. .get_num_images = disk_get_num_images,
  480. .replace_image_index = disk_replace_image_index,
  481. .add_image_index = disk_add_image_index,
  482. };
  483. static void disk_tray_open(void)
  484. {
  485. lprintf("cd tray open\n");
  486. disk_ejected = 1;
  487. }
  488. static void disk_tray_close(void)
  489. {
  490. lprintf("cd tray close\n");
  491. disk_ejected = 0;
  492. }
  493. static const char * const biosfiles_us[] = {
  494. "us_scd2_9306", "SegaCDBIOS9303", "us_scd1_9210", "bios_CD_U"
  495. };
  496. static const char * const biosfiles_eu[] = {
  497. "eu_mcd2_9306", "eu_mcd2_9303", "eu_mcd1_9210", "bios_CD_E"
  498. };
  499. static const char * const biosfiles_jp[] = {
  500. "jp_mcd2_921222", "jp_mcd1_9112", "jp_mcd1_9111", "bios_CD_J"
  501. };
  502. static void make_system_path(char *buf, size_t buf_size,
  503. const char *name, const char *ext)
  504. {
  505. const char *dir = NULL;
  506. if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) && dir) {
  507. snprintf(buf, buf_size, "%s%c%s%s", dir, SLASH, name, ext);
  508. }
  509. else {
  510. snprintf(buf, buf_size, "%s%s", name, ext);
  511. }
  512. }
  513. static const char *find_bios(int *region, const char *cd_fname)
  514. {
  515. const char * const *files;
  516. static char path[256];
  517. int i, count;
  518. FILE *f = NULL;
  519. if (*region == 4) { // US
  520. files = biosfiles_us;
  521. count = sizeof(biosfiles_us) / sizeof(char *);
  522. } else if (*region == 8) { // EU
  523. files = biosfiles_eu;
  524. count = sizeof(biosfiles_eu) / sizeof(char *);
  525. } else if (*region == 1 || *region == 2) {
  526. files = biosfiles_jp;
  527. count = sizeof(biosfiles_jp) / sizeof(char *);
  528. } else {
  529. return NULL;
  530. }
  531. for (i = 0; i < count; i++)
  532. {
  533. make_system_path(path, sizeof(path), files[i], ".bin");
  534. f = fopen(path, "rb");
  535. if (f != NULL)
  536. break;
  537. make_system_path(path, sizeof(path), files[i], ".zip");
  538. f = fopen(path, "rb");
  539. if (f != NULL)
  540. break;
  541. }
  542. if (f != NULL) {
  543. lprintf("using bios: %s\n", path);
  544. fclose(f);
  545. return path;
  546. }
  547. return NULL;
  548. }
  549. bool retro_load_game(const struct retro_game_info *info)
  550. {
  551. enum media_type_e media_type;
  552. static char carthw_path[256];
  553. size_t i;
  554. enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
  555. if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) {
  556. lprintf("RGB565 support required, sorry\n");
  557. return false;
  558. }
  559. if (info == NULL || info->path == NULL) {
  560. lprintf("info->path required\n");
  561. return false;
  562. }
  563. for (i = 0; i < sizeof(disks) / sizeof(disks[0]); i++) {
  564. if (disks[i].fname != NULL) {
  565. free(disks[i].fname);
  566. disks[i].fname = NULL;
  567. }
  568. }
  569. disk_current_index = 0;
  570. disk_count = 1;
  571. disks[0].fname = strdup(info->path);
  572. make_system_path(carthw_path, sizeof(carthw_path), "carthw", ".cfg");
  573. media_type = PicoLoadMedia(info->path, carthw_path,
  574. find_bios, NULL);
  575. switch (media_type) {
  576. case PM_BAD_DETECT:
  577. lprintf("Failed to detect ROM/CD image type.\n");
  578. return false;
  579. case PM_BAD_CD:
  580. lprintf("Invalid CD image\n");
  581. return false;
  582. case PM_BAD_CD_NO_BIOS:
  583. lprintf("Missing BIOS\n");
  584. return false;
  585. case PM_ERROR:
  586. lprintf("Load error\n");
  587. return false;
  588. default:
  589. break;
  590. }
  591. PicoLoopPrepare();
  592. PicoWriteSound = snd_write;
  593. memset(sndBuffer, 0, sizeof(sndBuffer));
  594. PsndOut = sndBuffer;
  595. PsndRerate(0);
  596. return true;
  597. }
  598. bool retro_load_game_special(unsigned game_type, const struct retro_game_info *info, size_t num_info)
  599. {
  600. return false;
  601. }
  602. void retro_unload_game(void)
  603. {
  604. }
  605. unsigned retro_get_region(void)
  606. {
  607. return Pico.m.pal ? RETRO_REGION_PAL : RETRO_REGION_NTSC;
  608. }
  609. void *retro_get_memory_data(unsigned id)
  610. {
  611. if (id != RETRO_MEMORY_SAVE_RAM)
  612. return NULL;
  613. if (PicoAHW & PAHW_MCD)
  614. return Pico_mcd->bram;
  615. else
  616. return SRam.data;
  617. }
  618. size_t retro_get_memory_size(unsigned id)
  619. {
  620. if (id != RETRO_MEMORY_SAVE_RAM)
  621. return 0;
  622. if (PicoAHW & PAHW_MCD)
  623. // bram
  624. return 0x2000;
  625. else
  626. return SRam.size;
  627. }
  628. void retro_reset(void)
  629. {
  630. PicoReset();
  631. }
  632. static const unsigned short retro_pico_map[] = {
  633. [RETRO_DEVICE_ID_JOYPAD_B] = 1 << GBTN_B,
  634. [RETRO_DEVICE_ID_JOYPAD_Y] = 1 << GBTN_A,
  635. [RETRO_DEVICE_ID_JOYPAD_SELECT] = 1 << GBTN_MODE,
  636. [RETRO_DEVICE_ID_JOYPAD_START] = 1 << GBTN_START,
  637. [RETRO_DEVICE_ID_JOYPAD_UP] = 1 << GBTN_UP,
  638. [RETRO_DEVICE_ID_JOYPAD_DOWN] = 1 << GBTN_DOWN,
  639. [RETRO_DEVICE_ID_JOYPAD_LEFT] = 1 << GBTN_LEFT,
  640. [RETRO_DEVICE_ID_JOYPAD_RIGHT] = 1 << GBTN_RIGHT,
  641. [RETRO_DEVICE_ID_JOYPAD_A] = 1 << GBTN_C,
  642. [RETRO_DEVICE_ID_JOYPAD_X] = 1 << GBTN_Y,
  643. [RETRO_DEVICE_ID_JOYPAD_L] = 1 << GBTN_X,
  644. [RETRO_DEVICE_ID_JOYPAD_R] = 1 << GBTN_Z,
  645. };
  646. #define RETRO_PICO_MAP_LEN (sizeof(retro_pico_map) / sizeof(retro_pico_map[0]))
  647. static void snd_write(int len)
  648. {
  649. audio_batch_cb(PsndOut, len / 4);
  650. }
  651. static enum input_device input_name_to_val(const char *name)
  652. {
  653. if (strcmp(name, "3 button pad") == 0)
  654. return PICO_INPUT_PAD_3BTN;
  655. if (strcmp(name, "6 button pad") == 0)
  656. return PICO_INPUT_PAD_6BTN;
  657. if (strcmp(name, "None") == 0)
  658. return PICO_INPUT_NOTHING;
  659. lprintf("invalid picodrive_input: '%s'\n", name);
  660. return PICO_INPUT_PAD_3BTN;
  661. }
  662. static void update_variables(void)
  663. {
  664. struct retro_variable var;
  665. var.value = NULL;
  666. var.key = "picodrive_input1";
  667. if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
  668. PicoSetInputDevice(0, input_name_to_val(var.value));
  669. var.value = NULL;
  670. var.key = "picodrive_input2";
  671. if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
  672. PicoSetInputDevice(1, input_name_to_val(var.value));
  673. var.value = NULL;
  674. var.key = "picodrive_sprlim";
  675. if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
  676. if (strcmp(var.value, "enabled") == 0)
  677. PicoOpt |= POPT_DIS_SPRITE_LIM;
  678. else
  679. PicoOpt &= ~POPT_DIS_SPRITE_LIM;
  680. }
  681. var.value = NULL;
  682. var.key = "picodrive_ramcart";
  683. if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
  684. if (strcmp(var.value, "enabled") == 0)
  685. PicoOpt |= POPT_EN_MCD_RAMCART;
  686. else
  687. PicoOpt &= ~POPT_EN_MCD_RAMCART;
  688. }
  689. #ifdef DRC_SH2
  690. var.value = NULL;
  691. var.key = "picodrive_drc";
  692. if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
  693. if (strcmp(var.value, "enabled") == 0)
  694. PicoOpt |= POPT_EN_DRC;
  695. else
  696. PicoOpt &= ~POPT_EN_DRC;
  697. }
  698. #endif
  699. }
  700. void retro_run(void)
  701. {
  702. bool updated = false;
  703. int pad, i;
  704. if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
  705. update_variables();
  706. input_poll_cb();
  707. PicoPad[0] = PicoPad[1] = 0;
  708. for (pad = 0; pad < 2; pad++)
  709. for (i = 0; i < RETRO_PICO_MAP_LEN; i++)
  710. if (input_state_cb(pad, RETRO_DEVICE_JOYPAD, 0, i))
  711. PicoPad[pad] |= retro_pico_map[i];
  712. PicoFrame();
  713. video_cb((short *)vout_buf + vout_offset,
  714. vout_width, vout_height, vout_width * 2);
  715. }
  716. void retro_init(void)
  717. {
  718. int level;
  719. #ifdef IOS
  720. emu_log = fopen("/User/Documents/PicoDrive.log", "w");
  721. if (emu_log == NULL)
  722. emu_log = fopen("PicoDrive.log", "w");
  723. if (emu_log == NULL)
  724. #endif
  725. emu_log = stdout;
  726. level = 0;
  727. environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level);
  728. environ_cb(RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE, &disk_control);
  729. PicoOpt = POPT_EN_STEREO|POPT_EN_FM|POPT_EN_PSG|POPT_EN_Z80
  730. | POPT_EN_MCD_PCM|POPT_EN_MCD_CDDA|POPT_EN_MCD_GFX
  731. | POPT_EN_32X|POPT_EN_PWM
  732. | POPT_ACC_SPRITES|POPT_DIS_32C_BORDER;
  733. #ifdef __arm__
  734. PicoOpt |= POPT_EN_DRC;
  735. #endif
  736. PsndRate = 44100;
  737. PicoAutoRgnOrder = 0x184; // US, EU, JP
  738. vout_width = 320;
  739. vout_height = 240;
  740. vout_buf = malloc(VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2);
  741. PicoInit();
  742. PicoDrawSetOutFormat(PDF_RGB555, 0);
  743. PicoDrawSetOutBuf(vout_buf, vout_width * 2);
  744. //PicoMessage = plat_status_msg_busy_next;
  745. PicoMCDopenTray = disk_tray_open;
  746. PicoMCDcloseTray = disk_tray_close;
  747. update_variables();
  748. }
  749. void retro_deinit(void)
  750. {
  751. PicoExit();
  752. }