Accept RETRO_DEVICE_ANALOG.
[bsnes:bsnes.git] / bsnes / target-libretro / libretro.cpp
1 #include "libretro.h"
2 #include <sfc/sfc.hpp>
3
4 #include <nall/snes/cartridge.hpp>
5 #include <nall/gb/cartridge.hpp>
6 #include <nall/stream/mmap.hpp>
7 using namespace nall;
8
9 const uint8 iplrom[64] = {
10 /*ffc0*/  0xcd, 0xef,        //mov   x,#$ef
11 /*ffc2*/  0xbd,              //mov   sp,x
12 /*ffc3*/  0xe8, 0x00,        //mov   a,#$00
13 /*ffc5*/  0xc6,              //mov   (x),a
14 /*ffc6*/  0x1d,              //dec   x
15 /*ffc7*/  0xd0, 0xfc,        //bne   $ffc5
16 /*ffc9*/  0x8f, 0xaa, 0xf4,  //mov   $f4,#$aa
17 /*ffcc*/  0x8f, 0xbb, 0xf5,  //mov   $f5,#$bb
18 /*ffcf*/  0x78, 0xcc, 0xf4,  //cmp   $f4,#$cc
19 /*ffd2*/  0xd0, 0xfb,        //bne   $ffcf
20 /*ffd4*/  0x2f, 0x19,        //bra   $ffef
21 /*ffd6*/  0xeb, 0xf4,        //mov   y,$f4
22 /*ffd8*/  0xd0, 0xfc,        //bne   $ffd6
23 /*ffda*/  0x7e, 0xf4,        //cmp   y,$f4
24 /*ffdc*/  0xd0, 0x0b,        //bne   $ffe9
25 /*ffde*/  0xe4, 0xf5,        //mov   a,$f5
26 /*ffe0*/  0xcb, 0xf4,        //mov   $f4,y
27 /*ffe2*/  0xd7, 0x00,        //mov   ($00)+y,a
28 /*ffe4*/  0xfc,              //inc   y
29 /*ffe5*/  0xd0, 0xf3,        //bne   $ffda
30 /*ffe7*/  0xab, 0x01,        //inc   $01
31 /*ffe9*/  0x10, 0xef,        //bpl   $ffda
32 /*ffeb*/  0x7e, 0xf4,        //cmp   y,$f4
33 /*ffed*/  0x10, 0xeb,        //bpl   $ffda
34 /*ffef*/  0xba, 0xf6,        //movw  ya,$f6
35 /*fff1*/  0xda, 0x00,        //movw  $00,ya
36 /*fff3*/  0xba, 0xf4,        //movw  ya,$f4
37 /*fff5*/  0xc4, 0xf4,        //mov   $f4,a
38 /*fff7*/  0xdd,              //mov   a,y
39 /*fff8*/  0x5d,              //mov   x,a
40 /*fff9*/  0xd0, 0xdb,        //bne   $ffd6
41 /*fffb*/  0x1f, 0x00, 0x00,  //jmp   ($0000+x)
42 /*fffe*/  0xc0, 0xff         //reset vector location ($ffc0)
43 };
44
45 struct Callbacks : Emulator::Interface::Bind {
46   retro_video_refresh_t pvideo_refresh;
47   retro_audio_sample_t paudio_sample;
48   retro_input_poll_t pinput_poll;
49   retro_input_state_t pinput_state;
50   retro_environment_t penviron;
51   bool overscan;
52
53   Emulator::Interface *iface;
54
55   string basename;
56   uint16_t buffer[512 * 448];
57   SuperFamicom::Video video;
58
59   static unsigned snes_to_retro(unsigned device) {
60     switch ((SuperFamicom::Input::Device)device) {
61        default:
62        case SuperFamicom::Input::Device::None:       return RETRO_DEVICE_NONE;
63        case SuperFamicom::Input::Device::Joypad:     return RETRO_DEVICE_JOYPAD;
64        case SuperFamicom::Input::Device::Multitap:   return RETRO_DEVICE_JOYPAD_MULTITAP;
65        case SuperFamicom::Input::Device::Mouse:      return RETRO_DEVICE_MOUSE;
66        case SuperFamicom::Input::Device::SuperScope: return RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE;
67        case SuperFamicom::Input::Device::Justifier:  return RETRO_DEVICE_LIGHTGUN_JUSTIFIER;
68        case SuperFamicom::Input::Device::Justifiers: return RETRO_DEVICE_LIGHTGUN_JUSTIFIERS;
69     }
70   }
71
72   // TODO: Properly map Mouse/Lightguns.
73   static unsigned snes_to_retro(unsigned, unsigned id) {
74     return id;
75   }
76
77   static SuperFamicom::Input::Device retro_to_snes(unsigned device) {
78     switch (device) {
79        default:
80        case RETRO_DEVICE_NONE:                 return SuperFamicom::Input::Device::None;
81        case RETRO_DEVICE_JOYPAD:               return SuperFamicom::Input::Device::Joypad;
82        case RETRO_DEVICE_ANALOG:               return SuperFamicom::Input::Device::Joypad;
83        case RETRO_DEVICE_JOYPAD_MULTITAP:      return SuperFamicom::Input::Device::Multitap;
84        case RETRO_DEVICE_MOUSE:                return SuperFamicom::Input::Device::Mouse;
85        case RETRO_DEVICE_LIGHTGUN_SUPER_SCOPE: return SuperFamicom::Input::Device::SuperScope;
86        case RETRO_DEVICE_LIGHTGUN_JUSTIFIER:   return SuperFamicom::Input::Device::Justifier;
87        case RETRO_DEVICE_LIGHTGUN_JUSTIFIERS:  return SuperFamicom::Input::Device::Justifiers;
88     }
89   }
90
91   void videoRefresh(const uint32_t *data, unsigned pitch, unsigned width, unsigned height) {
92
93     pitch >>= 2;
94
95     if (!overscan) {
96       data += 8 * 1024;
97
98       if (height == 240)
99         height = 224;
100       else if (height == 480)
101         height = 448;
102     }
103
104     uint16_t *dp = buffer;
105     const uint32_t *sp = data;
106     for(unsigned y = 0; y < height; y++, sp += pitch) {
107       for(unsigned x = 0; x < width; x++) {
108         *dp++ = sp[x];
109       }
110     }
111
112     pvideo_refresh(buffer, width, height, width << 1);
113     pinput_poll();
114   }
115
116   void audioSample(int16_t left, int16_t right) {
117     paudio_sample(left, right);
118   }
119
120   int16_t inputPoll(unsigned port, unsigned device, unsigned id) {
121     if(id > 11) return 0;
122     return pinput_state(port, snes_to_retro(device), 0, snes_to_retro(device, id));
123   }
124
125   void loadRequest(unsigned id, const string &p) {
126     string load_path = {path(0), p};
127     fprintf(stderr, "bsnes: Load_path: %s\n", (const char*)load_path);
128     if(file::exists(load_path)) {
129       mmapstream stream(load_path);
130       iface->load(id, stream);
131     } else {
132       fprintf(stderr, "bsnes: Cannot find path: \"%s\".\n", (const char*)load_path);
133     }
134   }
135
136   string path(unsigned) {
137     return string(basename);
138   }
139
140   uint32_t videoColor(unsigned, uint16_t r, uint16_t g, uint16_t b) {
141     r >>= 11;
142     g >>= 11;
143     b >>= 11;
144     return (r << 10) | (g << 5) | (b << 0);
145   }
146 };
147
148 static Callbacks core_bind;
149
150 struct Interface : public SuperFamicom::Interface {
151   SuperFamicomCartridge::Mode mode;
152
153   void setCheats(const lstring &list = lstring());
154
155   Interface(); 
156
157   void init() {
158     updatePalette();
159   }
160 };
161
162 struct GBInterface : public GameBoy::Interface {
163   GBInterface() { bind = &core_bind; }
164   void init() {
165     updatePalette();
166   }
167 };
168
169 static Interface core_interface;
170 static GBInterface core_gb_interface;
171
172 Interface::Interface() {
173   bind = &core_bind;
174   core_bind.iface = &core_interface;
175 }
176
177 void Interface::setCheats(const lstring &list) {
178   if(core_interface.mode == SuperFamicomCartridge::ModeSuperGameBoy) {
179     GameBoy::cheat.reset();
180     for(auto &code : list) {
181       lstring codelist;
182       codelist.split("+", code);
183       for(auto &part : codelist) {
184         unsigned addr, data, comp;
185         if(GameBoy::Cheat::decode(part, addr, data, comp)) {
186           GameBoy::cheat.append({addr, data, comp});
187         }
188       }
189     }
190     GameBoy::cheat.synchronize();
191     return;
192   }
193
194   SuperFamicom::cheat.reset();
195   for(auto &code : list) {
196     lstring codelist;
197     codelist.split("+", code);
198     for(auto &part : codelist) {
199       unsigned addr, data;
200       if(SuperFamicom::Cheat::decode(part, addr, data)) {
201         SuperFamicom::cheat.append({addr, data});
202       }
203     }
204   }
205
206   SuperFamicom::cheat.synchronize();
207 }
208
209 unsigned retro_api_version(void) {
210   return RETRO_API_VERSION;
211 }
212
213 void retro_set_environment(retro_environment_t environ_cb)        { core_bind.penviron       = environ_cb; }
214 void retro_set_video_refresh(retro_video_refresh_t video_refresh) { core_bind.pvideo_refresh = video_refresh; }
215 void retro_set_audio_sample(retro_audio_sample_t audio_sample)    { core_bind.paudio_sample  = audio_sample; }
216 void retro_set_audio_sample_batch(retro_audio_sample_batch_t)     {}
217 void retro_set_input_poll(retro_input_poll_t input_poll)          { core_bind.pinput_poll    = input_poll; }
218 void retro_set_input_state(retro_input_state_t input_state)       { core_bind.pinput_state   = input_state; }
219
220 void retro_set_controller_port_device(unsigned port, unsigned device) {
221   if (port < 2)
222     SuperFamicom::input.connect(port, Callbacks::retro_to_snes(device));
223 }
224
225 void retro_init(void) {
226   SuperFamicom::interface = &core_interface;
227   GameBoy::interface = &core_gb_interface;
228
229   core_interface.init();
230
231   memcpy(SuperFamicom::smp.iplrom, iplrom, 64);
232   SuperFamicom::system.init();
233   SuperFamicom::input.connect(SuperFamicom::Controller::Port1, SuperFamicom::Input::Device::Joypad);
234   SuperFamicom::input.connect(SuperFamicom::Controller::Port2, SuperFamicom::Input::Device::Joypad);
235 }
236
237 void retro_deinit(void) {
238   SuperFamicom::system.term();
239 }
240
241 void retro_reset(void) {
242   SuperFamicom::system.reset();
243 }
244
245 void retro_run(void) {
246   SuperFamicom::system.run();
247 }
248
249 size_t retro_serialize_size(void) {
250   return SuperFamicom::system.serialize_size();
251 }
252
253 bool retro_serialize(void *data, size_t size) {
254   SuperFamicom::system.runtosave();
255   serializer s = SuperFamicom::system.serialize();
256   if(s.size() > size) return false;
257   memcpy(data, s.data(), s.size());
258   return true;
259 }
260
261 bool retro_unserialize(const void *data, size_t size) {
262   serializer s((const uint8_t*)data, size);
263   return SuperFamicom::system.unserialize(s);
264 }
265
266 struct CheatList {
267   bool enable;
268   string code;
269   CheatList() : enable(false) {}
270 };
271
272 static linear_vector<CheatList> cheatList;
273
274 void retro_cheat_reset(void) {
275   cheatList.reset();
276   core_interface.setCheats();
277 }
278
279 void retro_cheat_set(unsigned index, bool enable, const char *code) {
280   cheatList[index].enable = enable;
281   cheatList[index].code = code;
282   lstring list;
283
284   for(unsigned n = 0; n < cheatList.size(); n++) {
285     if(cheatList[n].enable) list.append(cheatList[n].code);
286   }
287
288   core_interface.setCheats(list);
289 }
290
291 void retro_get_system_info(struct retro_system_info *info) {
292   static string version("v", Emulator::Version, " (", SuperFamicom::Info::Profile, ")");
293   info->library_name     = "bSNES";
294   info->library_version  = version;
295   info->valid_extensions = 0;
296   info->need_fullpath    = false;
297 }
298
299 void retro_get_system_av_info(struct retro_system_av_info *info) {
300   struct retro_system_timing timing = { 0.0, 32040.5 };
301   timing.fps = retro_get_region() == RETRO_REGION_NTSC ? 21477272.0 / 357366.0 : 21281370.0 / 425568.0;
302
303   if (!core_bind.penviron(RETRO_ENVIRONMENT_GET_OVERSCAN, &core_bind.overscan))
304      core_bind.overscan = false;
305
306   unsigned base_width = 256;
307   unsigned base_height = core_bind.overscan ? 240 : 224;
308   struct retro_game_geometry geom = { base_width, base_height, base_width << 1, base_height << 1 };
309
310   info->timing   = timing;
311   info->geometry = geom;
312 }
313
314 static bool snes_load_cartridge_normal(
315   const char *rom_xml, const uint8_t *rom_data, unsigned rom_size
316 ) {
317   string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SuperFamicomCartridge(rom_data, rom_size).markup;
318   SuperFamicom::cartridge.load(xmlrom, memorystream(rom_data, rom_size));
319   SuperFamicom::system.power();
320   return true;
321 }
322
323 static bool snes_load_cartridge_bsx_slotted(
324   const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
325   const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size
326 ) {
327   string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SuperFamicomCartridge(rom_data, rom_size).markup;
328   string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SuperFamicomCartridge(bsx_data, bsx_size).markup;
329
330   SuperFamicom::bsxflash.memory.copy(memorystream(bsx_data, bsx_size));
331   SuperFamicom::cartridge.load(xmlrom, memorystream(rom_data, rom_size));
332
333   SuperFamicom::system.power();
334   return true;
335 }
336
337 static bool snes_load_cartridge_bsx(
338   const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
339   const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size
340 ) {
341   string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SuperFamicomCartridge(rom_data, rom_size).markup;
342   string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SuperFamicomCartridge(bsx_data, bsx_size).markup;
343
344   SuperFamicom::bsxflash.memory.copy(memorystream(bsx_data, bsx_size));
345   SuperFamicom::cartridge.load(xmlrom, memorystream(rom_data, rom_size));
346
347   SuperFamicom::system.power();
348   return true;
349 }
350
351 static bool snes_load_cartridge_sufami_turbo(
352   const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
353   const char *sta_xml, const uint8_t *sta_data, unsigned sta_size,
354   const char *stb_xml, const uint8_t *stb_data, unsigned stb_size
355 ) {
356   string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SuperFamicomCartridge(rom_data, rom_size).markup;
357   string xmlsta = (sta_xml && *sta_xml) ? string(sta_xml) : SuperFamicomCartridge(sta_data, sta_size).markup;
358   string xmlstb = (stb_xml && *stb_xml) ? string(stb_xml) : SuperFamicomCartridge(stb_data, stb_size).markup;
359
360   if(sta_data) SuperFamicom::sufamiturbo.slotA.rom.copy(memorystream(sta_data, sta_size));
361   if(stb_data) SuperFamicom::sufamiturbo.slotB.rom.copy(memorystream(stb_data, stb_size));
362   SuperFamicom::cartridge.load(xmlrom, memorystream(rom_data, rom_size));
363
364   SuperFamicom::system.power();
365   return true;
366 }
367
368 static bool snes_load_cartridge_super_game_boy(
369   const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
370   const char *dmg_xml, const uint8_t *dmg_data, unsigned dmg_size
371 ) {
372   string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SuperFamicomCartridge(rom_data, rom_size).markup;
373
374   if(dmg_data) {
375     //GameBoyCartridge needs to modify dmg_data (for MMM01 emulation); so copy data
376     uint8_t *data = new uint8_t[dmg_size];
377     memcpy(data, dmg_data, dmg_size);
378     string xmldmg = (dmg_xml && *dmg_xml) ? string(dmg_xml) : GameBoyCartridge(data, dmg_size).markup;
379     GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy, xmldmg, memorystream(data, dmg_size));
380     delete[] data;
381   }
382
383   SuperFamicom::cartridge.load(xmlrom, memorystream(rom_data, rom_size));
384   SuperFamicom::system.power();
385   return true;
386 }
387
388 bool retro_load_game(const struct retro_game_info *info) {
389   retro_cheat_reset();
390   if (info->path) {
391     core_bind.basename = info->path;
392     char *dot = strrchr(core_bind.basename(), '/');
393     if (!dot)
394        dot = strrchr(core_bind.basename(), '\\');
395
396     if (dot)
397        dot[1] = '\0';
398   }
399
400   core_interface.mode = SuperFamicomCartridge::ModeNormal;
401   return snes_load_cartridge_normal(info->meta, (const uint8_t*)info->data, info->size);
402 }
403
404 bool retro_load_game_special(unsigned game_type,
405       const struct retro_game_info *info, size_t num_info) {
406
407   retro_cheat_reset();
408   if (info[0].path) {
409     core_bind.basename = info[0].path;
410     char *dot = strrchr(core_bind.basename(), '.');
411     if (dot)
412        *dot = '\0';
413   }
414
415   switch (game_type) {
416      case RETRO_GAME_TYPE_BSX:
417        core_interface.mode = SuperFamicomCartridge::ModeBsx;
418        return num_info == 2 && snes_load_cartridge_bsx(info[0].meta, (const uint8_t*)info[0].data, info[0].size,
419              info[1].meta, (const uint8_t*)info[1].data, info[1].size);
420        
421      case RETRO_GAME_TYPE_BSX_SLOTTED:
422        core_interface.mode = SuperFamicomCartridge::ModeBsxSlotted;
423        return num_info == 2 && snes_load_cartridge_bsx_slotted(info[0].meta, (const uint8_t*)info[0].data, info[0].size,
424              info[1].meta, (const uint8_t*)info[1].data, info[1].size);
425
426      case RETRO_GAME_TYPE_SUPER_GAME_BOY:
427        core_interface.mode = SuperFamicomCartridge::ModeSuperGameBoy;
428        return num_info == 2 && snes_load_cartridge_super_game_boy(info[0].meta, (const uint8_t*)info[0].data, info[0].size,
429              info[1].meta, (const uint8_t*)info[1].data, info[1].size);
430
431      case RETRO_GAME_TYPE_SUFAMI_TURBO:
432        core_interface.mode = SuperFamicomCartridge::ModeSufamiTurbo;
433        return num_info == 3 && snes_load_cartridge_sufami_turbo(info[0].meta, (const uint8_t*)info[0].data, info[0].size,
434              info[1].meta, (const uint8_t*)info[1].data, info[1].size,
435              info[2].meta, (const uint8_t*)info[2].data, info[2].size);
436
437      default:
438        return false;
439   }
440 }
441
442 void retro_unload_game(void) {
443   SuperFamicom::cartridge.unload();
444 }
445
446 unsigned retro_get_region(void) {
447   return SuperFamicom::system.region() == SuperFamicom::System::Region::NTSC ? 0 : 1;
448 }
449
450 void* retro_get_memory_data(unsigned id) {
451   if(SuperFamicom::cartridge.loaded() == false) return 0;
452
453   switch(id) {
454     case RETRO_MEMORY_SAVE_RAM:
455       return SuperFamicom::cartridge.ram.data();
456     case RETRO_MEMORY_RTC:
457       if(SuperFamicom::cartridge.has_srtc()) return SuperFamicom::srtc.rtc;
458       if(SuperFamicom::cartridge.has_spc7110rtc()) return SuperFamicom::spc7110.rtc;
459       return 0;
460     case RETRO_MEMORY_SNES_BSX_RAM:
461       if(core_interface.mode != SuperFamicomCartridge::ModeBsx) break;
462       return SuperFamicom::bsxcartridge.sram.data();
463     case RETRO_MEMORY_SNES_BSX_PRAM:
464       if(core_interface.mode != SuperFamicomCartridge::ModeBsx) break;
465       return SuperFamicom::bsxcartridge.psram.data();
466     case RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM:
467       if(core_interface.mode != SuperFamicomCartridge::ModeSufamiTurbo) break;
468       return SuperFamicom::sufamiturbo.slotA.ram.data();
469     case RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM:
470       if(core_interface.mode != SuperFamicomCartridge::ModeSufamiTurbo) break;
471       return SuperFamicom::sufamiturbo.slotB.ram.data();
472     case RETRO_MEMORY_SNES_GAME_BOY_RAM:
473       if(core_interface.mode != SuperFamicomCartridge::ModeSuperGameBoy) break;
474       return GameBoy::cartridge.ramdata;
475
476     case RETRO_MEMORY_SYSTEM_RAM:
477       return SuperFamicom::cpu.wram;
478     case RETRO_MEMORY_VIDEO_RAM:
479       return SuperFamicom::ppu.vram;
480   }
481
482   return 0;
483 }
484
485 size_t retro_get_memory_size(unsigned id) {
486   if(SuperFamicom::cartridge.loaded() == false) return 0;
487   size_t size = 0;
488
489   switch(id) {
490     case RETRO_MEMORY_SAVE_RAM:
491       size = SuperFamicom::cartridge.ram.size();
492       break;
493     case RETRO_MEMORY_RTC:
494       if(SuperFamicom::cartridge.has_srtc() || SuperFamicom::cartridge.has_spc7110rtc()) size = 20;
495       break;
496     case RETRO_MEMORY_SNES_BSX_RAM:
497       if(core_interface.mode != SuperFamicomCartridge::ModeBsx) break;
498       size = SuperFamicom::bsxcartridge.sram.size();
499       break;
500     case RETRO_MEMORY_SNES_BSX_PRAM:
501       if(core_interface.mode != SuperFamicomCartridge::ModeBsx) break;
502       size = SuperFamicom::bsxcartridge.psram.size();
503       break;
504     case RETRO_MEMORY_SNES_SUFAMI_TURBO_A_RAM:
505       if(core_interface.mode != SuperFamicomCartridge::ModeSufamiTurbo) break;
506       size = SuperFamicom::sufamiturbo.slotA.ram.size();
507       break;
508     case RETRO_MEMORY_SNES_SUFAMI_TURBO_B_RAM:
509       if(core_interface.mode != SuperFamicomCartridge::ModeSufamiTurbo) break;
510       size = SuperFamicom::sufamiturbo.slotB.ram.size();
511       break;
512     case RETRO_MEMORY_SNES_GAME_BOY_RAM:
513       if(core_interface.mode != SuperFamicomCartridge::ModeSuperGameBoy) break;
514       size = GameBoy::cartridge.ramsize;
515       break;
516
517     case RETRO_MEMORY_SYSTEM_RAM:
518       size = 128 * 1024;
519       break;
520     case RETRO_MEMORY_VIDEO_RAM:
521       size = 64 * 1024;
522       break;
523   }
524
525   if(size == -1U) size = 0;
526   return size;
527 }
528