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