--- ../bsnes-libretro/target-libretro/libretro.cpp	2015-04-23 18:11:06.227925641 +0200
+++ target-libretro/libretro.cpp	2015-04-23 17:17:56.059865750 +0200
@@ -64,9 +64,21 @@
 /*fffe*/  0xc0, 0xff         //reset vector location ($ffc0)
 };
 
+static void retro_log_default(enum retro_log_level level, const char *fmt, ...)
+{
+  fprintf(stderr, "[bsnes]: ");
+  va_list args;
+  va_start(args, fmt);
+  vfprintf(stderr, fmt, args);
+  va_end(args);
+}
+static retro_log_printf_t output;
+
+static const char * read_opt(const char * name, const char * defval);
+
 struct Callbacks : Emulator::Interface::Bind {
   retro_video_refresh_t pvideo_refresh;
-  retro_audio_sample_batch_t paudio_sample;
+  retro_audio_sample_batch_t paudio;
   retro_input_poll_t pinput_poll;
   retro_input_state_t pinput_state;
   retro_environment_t penviron;
@@ -129,7 +141,7 @@
     uint16_t video_buffer_16[512 * 480];
   };
 
-  void videoRefresh(const uint32_t *palette, const uint32_t *data, unsigned pitch, unsigned width, unsigned height) {
+  void videoRefresh(const uint32_t* palette, const uint32_t* data, unsigned pitch, unsigned width, unsigned height) override {
     if (!overscan) {
       data += 8 * 1024;
 
@@ -161,20 +173,26 @@
     }
   }
 
-  void audioSample(int16_t left, int16_t right)
-  {
-     const int16_t samples[2] = { left, right };
-     paudio_sample(samples, 1);
+  int16_t sampleBuf[128];
+  unsigned int sampleBufPos;
+
+  void audioSample(int16_t left, int16_t right) override {
+    sampleBuf[sampleBufPos++] = left;
+    sampleBuf[sampleBufPos++] = right;
+    if(sampleBufPos==128) {
+      paudio(sampleBuf, 64);
+      sampleBufPos = 0;
+    }
   }
 
-  int16_t inputPoll(unsigned port, unsigned device, unsigned id) {
+  int16_t inputPoll(unsigned port, unsigned device, unsigned id) override {
     if(id > 11) return 0;
     return pinput_state(port, snes_to_retro(device), 0, snes_to_retro(device, id));
   }
 
-  void saveRequest(unsigned id, string p) {
+  void saveRequest(unsigned id, string p) override {
     if (manifest) {
-      fprintf(stderr, "[bsnes]: [Save]: ID %u, Request \"%s\".\n", id, (const char*)p);
+      output(RETRO_LOG_INFO, "[Save]: ID %u, Request \"%s\".\n", id, (const char*)p);
       string save_path = {path(0), p};
       filestream stream(save_path, file::mode::write);
       iface->save(id, stream);
@@ -196,11 +214,11 @@
         mmapstream stream(load_path);
         iface->load(id, stream);
       } else {
-        fprintf(stderr, "[bsnes]: Cannot find requested file in system directory: \"%s\".\n", (const char*)load_path);
+        output(RETRO_LOG_ERROR, "Cannot find requested file in system directory: \"%s\".\n", (const char*)load_path);
         load_request_error = true;
       }
     } else {
-      fprintf(stderr, "[bsnes]: Cannot find requested file: \"%s\" in ROM directory nor system directory.\n", (const char*)p);
+      output(RETRO_LOG_ERROR, "Cannot find requested file: \"%s\" in ROM directory nor system directory.\n", (const char*)p);
       load_request_error = true;
     }
   }
@@ -231,7 +249,7 @@
   }
 
   void loadRequestManifest(unsigned id, const string& p) {
-    fprintf(stderr, "[bsnes]: [Manifest]: ID %u, Request \"%s\".\n", id, (const char*)p);
+    output(RETRO_LOG_INFO, "[Manifest]: ID %u, Request \"%s\".\n", id, (const char*)p);
     switch(id) {
       case SuperFamicom::ID::IPLROM:
         loadIPLROM(id);
@@ -248,7 +266,7 @@
   }
 
   void loadRequestMemory(unsigned id, const string& p) {
-    fprintf(stderr, "[bsnes]: [Memory]: ID %u, Request \"%s\".\n", id, (const char*)p);
+    output(RETRO_LOG_INFO, "[Memory]: ID %u, Request \"%s\".\n", id, (const char*)p);
     switch(id) {
       case SuperFamicom::ID::Manifest:
         loadManifest(id);
@@ -264,7 +282,7 @@
       case SuperFamicom::ID::SDD1ROM:
       case SuperFamicom::ID::HitachiDSPROM:
       case SuperFamicom::ID::SPC7110PROM:
-        fprintf(stderr, "[bsnes]: Load ROM.\n");
+        output(RETRO_LOG_INFO, "Load ROM.\n");
         loadROM(id);
         break;
 
@@ -319,37 +337,37 @@
         break;
 
       default:
-        fprintf(stderr, "[bsnes]: Load BIOS.\n");
+        output(RETRO_LOG_INFO, "Load BIOS.\n");
         loadFile(id, p);
         break;
     }
   }
 
-  void loadRequest(unsigned id, string p) {
+  void loadRequest(unsigned id, string p) override {
     if (manifest)
        loadRequestManifest(id, p);
     else
        loadRequestMemory(id, p);
-    fprintf(stderr, "[bsnes]: Complete load request.\n");
+    output(RETRO_LOG_INFO, "Complete load request.\n");
   }
 
-  void loadRequest(unsigned id, string p, string manifest) {
+  void loadRequest(unsigned id, string p, string manifest) override {
     switch (id) {
       case SuperFamicom::ID::SuperGameBoy:
-        fprintf(stderr, "[bsnes]: Loading GB ROM.\n");
+        output(RETRO_LOG_INFO, "Loading GB ROM.\n");
         loadSGBROMManifest(id);
         break;
 
       default:
-        fprintf(stderr, "[bsnes]: Didn't do anything with loadRequest (3 arg).\n");
+        output(RETRO_LOG_INFO, "Didn't do anything with loadRequest (3 arg).\n");
     }
   }
 
-  string path(unsigned) {
+  string path(unsigned) override {
     return string(basename);
   }
 
-  uint32_t videoColor(unsigned, uint16_t, uint16_t r, uint16_t g, uint16_t b) {
+  uint32_t videoColor(unsigned, uint16_t, uint16_t r, uint16_t g, uint16_t b) override {
     r >>= 8;
     g >>= 8;
     b >>= 8;
@@ -357,10 +375,43 @@
     if (video_fmt == video_fmt_16) return (r>>3 << 11) | (g>>2 << 5) | (b>>3 << 0);
     if (video_fmt == video_fmt_15) return (r>>3 << 10) | (g>>3 << 5) | (b>>3 << 0);
   }
+
+  void notify(string text) {
+    output(RETRO_LOG_ERROR, "%s\n", (const char*)text);
+  }
+
+  unsigned altImplementation(unsigned item) override {
+    if (item==SuperFamicom::Alt::ForDSP)
+    {
+      if (!strcmp(read_opt("bsnes_chip_hle", "LLE"), "HLE")) return SuperFamicom::Alt::DSP::HLE;
+      else return SuperFamicom::Alt::DSP::LLE;
+    }
+#ifdef EXPERIMENTAL_FEATURES
+    if (item==SuperFamicom::Alt::ForSuperGameBoy)
+    {
+      if (!strcmp(read_opt("bsnes_sgb_core", "Internal"), "Gambatte")) return SuperFamicom::Alt::SuperGameBoy::External;
+      else return SuperFamicom::Alt::SuperGameBoy::Internal;
+    }
+#endif
+    return 0;
+  }
 };
 
 static Callbacks core_bind;
 
+static const char * read_opt(const char * name, const char * defval)
+{
+	struct retro_variable allowvar = { "bsnes_violate_accuracy", "No" };
+	core_bind.penviron(RETRO_ENVIRONMENT_GET_VARIABLE, (void*)&allowvar);
+	if (!strcmp(allowvar.value, "Yes"))
+	{
+		struct retro_variable var = {name, defval};
+		core_bind.penviron(RETRO_ENVIRONMENT_GET_VARIABLE, (void*)&var);
+		return var.value;
+	}
+	else return defval;
+}
+
 struct Interface : public SuperFamicom::Interface {
   SuperFamicomCartridge::Mode mode;
 
@@ -426,10 +477,28 @@
   return RETRO_API_VERSION;
 }
 
+static unsigned superfx_freq_orig;
+
 void retro_set_environment(retro_environment_t environ_cb)
 {
    core_bind.penviron = environ_cb;
 
+   static const struct retro_variable vars[] = {
+      { "bsnes_violate_accuracy", "Respect accuracy-impacting settings; No|Yes" },
+      { "bsnes_chip_hle", "Special chip accuracy; LLE|HLE" },
+      { "bsnes_superfx_overclock", "SuperFX speed; 100%|150%|200%|300%|400%|500%|1000%" },
+         //Any integer is usable here, but there is no such thing as "any integer" in core options.
+#ifdef EXPERIMENTAL_FEATURES
+      { "bsnes_sgb_core", "Super Game Boy core; Internal|Gambatte" },
+#endif
+      { NULL, NULL },
+   };
+   core_bind.penviron(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars);
+
+   static struct retro_log_callback log={retro_log_default};
+   core_bind.penviron(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, (void*)&log);
+   output=log.log;
+
    static const retro_subsystem_memory_info sgb_memory[] = {
       { "srm", RETRO_MEMORY_SNES_GAME_BOY_RAM },
       { "rtc", RETRO_MEMORY_SNES_GAME_BOY_RTC },
@@ -498,11 +567,19 @@
    environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports);
 }
 
-void retro_set_video_refresh(retro_video_refresh_t video_refresh) { core_bind.pvideo_refresh = video_refresh; }
-void retro_set_audio_sample(retro_audio_sample_t)    { }
-void retro_set_audio_sample_batch(retro_audio_sample_batch_t audio_sample) { core_bind.paudio_sample  = audio_sample; }
-void retro_set_input_poll(retro_input_poll_t input_poll)          { core_bind.pinput_poll    = input_poll; }
-void retro_set_input_state(retro_input_state_t input_state)       { core_bind.pinput_state   = input_state; }
+static void update_variables(void) {
+   if (SuperFamicom::cartridge.has_superfx()) {
+      const char * speed=read_opt("bsnes_superfx_overclock", "100%");
+      unsigned percent=strtoul(speed, NULL, 10);//we can assume that the input is one of our advertised options
+      SuperFamicom::superfx.frequency=(uint64)superfx_freq_orig*percent/100;
+   }
+}
+
+void retro_set_video_refresh(retro_video_refresh_t cb)           { core_bind.pvideo_refresh = cb; }
+void retro_set_audio_sample(retro_audio_sample_t)                { }
+void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb) { core_bind.paudio         = cb; }
+void retro_set_input_poll(retro_input_poll_t cb)                 { core_bind.pinput_poll    = cb; }
+void retro_set_input_state(retro_input_state_t cb)               { core_bind.pinput_state   = cb; }
 
 void retro_set_controller_port_device(unsigned port, unsigned device) {
   if (port < 2)
@@ -515,6 +592,8 @@
 
   core_interface.init();
   core_gb_interface.init();
+  
+  core_bind.sampleBufPos = 0;
 
   SuperFamicom::system.init();
   SuperFamicom::input.connect(SuperFamicom::Controller::Port1, SuperFamicom::Input::Device::Joypad);
@@ -530,7 +609,14 @@
 }
 
 void retro_run(void) {
+  bool updated = false;
+  if (core_bind.penviron(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
+    update_variables();
   SuperFamicom::system.run();
+  if(core_bind.sampleBufPos) {
+    core_bind.paudio(core_bind.sampleBuf, core_bind.sampleBufPos/2);
+    core_bind.sampleBufPos = 0;
+  }
 }
 
 size_t retro_serialize_size(void) {
@@ -550,6 +636,7 @@
   return SuperFamicom::system.unserialize(s);
 }
 
+#if 0
 struct CheatList {
   bool enable;
   string code;
@@ -557,27 +644,33 @@
 };
 
 static vector<CheatList> cheatList;
+#endif
 
 void retro_cheat_reset(void) {
+#if 0
   cheatList.reset();
   core_interface.setCheats();
+#endif
 }
 
 void retro_cheat_set(unsigned index, bool enable, const char *code) {
+#if 0
+  cheatList.reserve(index+1);
   cheatList[index].enable = enable;
   cheatList[index].code = code;
   lstring list;
-
+  
   for(unsigned n = 0; n < cheatList.size(); n++) {
     if(cheatList[n].enable) list.append(cheatList[n].code);
   }
-
+  
   core_interface.setCheats(list);
+#endif
 }
 
 void retro_get_system_info(struct retro_system_info *info) {
   static string version("v", Emulator::Version, " (", Emulator::Profile, ")");
-  info->library_name     = "bsnes";
+  info->library_name     = "bsnes-mercury";
   info->library_version  = version;
   info->valid_extensions = "sfc|smc|bml";
   info->need_fullpath    = false;
@@ -615,6 +708,19 @@
   }
 }
 
+static void output_multiline(enum retro_log_level level, char * data)
+{
+  while (true)
+  {
+    char* data_linebreak=strchr(data, '\n');
+    if (data_linebreak) *data_linebreak='\0';
+    if (*data) output(level, "%s\n", data);
+    if (!data_linebreak) break;
+    *data_linebreak='\n';
+    data=data_linebreak+1;
+  }
+}
+
 static bool snes_load_cartridge_normal(
   const char *rom_xml, const uint8_t *rom_data, unsigned rom_size
 ) {
@@ -623,7 +729,8 @@
   core_bind.rom_data = rom_data;
   core_bind.rom_size = rom_size;
   core_bind.xmlrom   = xmlrom;
-  fprintf(stderr, "[bsnes]: XML map:\n%s\n", (const char*)xmlrom);
+  output(RETRO_LOG_INFO, "BML map:\n");
+  output_multiline(RETRO_LOG_INFO, xmlrom.data());
   core_bind.iface->load(SuperFamicom::ID::SuperFamicom);
   SuperFamicom::system.power();
   return !core_bind.load_request_error;
@@ -689,8 +796,10 @@
 ) {
   string xmlrom_sgb = (rom_xml && *rom_xml) ? string(rom_xml) : SuperFamicomCartridge(rom_data, rom_size).markup;
   string xmlrom_gb  = (dmg_xml && *dmg_xml) ? string(dmg_xml) : GameBoyCartridge((uint8_t*)dmg_data, dmg_size).markup;
-  fprintf(stderr, "[bsnes]: Markup SGB: %s\n", (const char*)xmlrom_sgb);
-  fprintf(stderr, "[bsnes]: Markup GB: %s\n", (const char*)xmlrom_gb);
+  output(RETRO_LOG_INFO, "Markup SGB:\n");
+  output_multiline(RETRO_LOG_INFO, xmlrom_sgb.data());
+  output(RETRO_LOG_INFO, "Markup GB:\n");
+  output_multiline(RETRO_LOG_INFO, xmlrom_gb.data());
 
   core_bind.rom_data    = rom_data;
   core_bind.rom_size    = rom_size;
@@ -708,70 +817,70 @@
 static void init_descriptors(void)
 {
    struct retro_input_descriptor desc[] = {
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "B" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "A" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "X" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Y" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,     "L" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,     "R" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,   "Select" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" },
-
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "B" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "A" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "X" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Y" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,     "L" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,     "R" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,   "Select" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" },
-
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "B" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "A" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "X" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Y" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,     "L" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,     "R" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,   "Select" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" },
-
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "B" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "A" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "X" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Y" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,     "L" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,     "R" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,   "Select" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" },
-
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "B" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "A" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "X" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Y" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,     "L" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,     "R" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,   "Select" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" },
+      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,   "D-Pad Left" },
+      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,     "D-Pad Up" },
+      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,   "D-Pad Down" },
+      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT,  "D-Pad Right" },
+      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,      "B" },
+      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,      "A" },
+      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,      "X" },
+      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,      "Y" },
+      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,      "L" },
+      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,      "R" },
+      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
+      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,  "Start" },
+
+      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,   "D-Pad Left" },
+      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,     "D-Pad Up" },
+      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,   "D-Pad Down" },
+      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT,  "D-Pad Right" },
+      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,      "B" },
+      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,      "A" },
+      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,      "X" },
+      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,      "Y" },
+      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,      "L" },
+      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,      "R" },
+      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
+      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,  "Start" },
+
+      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,   "D-Pad Left" },
+      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,     "D-Pad Up" },
+      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,   "D-Pad Down" },
+      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT,  "D-Pad Right" },
+      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,      "B" },
+      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,      "A" },
+      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,      "X" },
+      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,      "Y" },
+      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,      "L" },
+      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,      "R" },
+      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
+      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,  "Start" },
+
+      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,   "D-Pad Left" },
+      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,     "D-Pad Up" },
+      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,   "D-Pad Down" },
+      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT,  "D-Pad Right" },
+      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,      "B" },
+      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,      "A" },
+      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,      "X" },
+      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,      "Y" },
+      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,      "L" },
+      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,      "R" },
+      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
+      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,  "Start" },
+
+      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,   "D-Pad Left" },
+      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,     "D-Pad Up" },
+      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,   "D-Pad Down" },
+      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT,  "D-Pad Right" },
+      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,      "B" },
+      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,      "A" },
+      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,      "X" },
+      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,      "Y" },
+      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,      "L" },
+      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,      "R" },
+      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
+      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,  "Start" },
 
       { 0 },
    };
@@ -811,9 +920,19 @@
   std::string manifest;
   if (core_bind.manifest)
     manifest = std::string((const char*)info->data, info->size); // Might not be 0 terminated.
-  return snes_load_cartridge_normal(core_bind.manifest ? manifest.data() : info->meta, data, size);
+  
+  bool ret=snes_load_cartridge_normal(core_bind.manifest ? manifest.data() : info->meta, data, size);
+  SuperFamicom::bus.libretro_mem_map.reverse();
+  retro_memory_map map={SuperFamicom::bus.libretro_mem_map.data(), SuperFamicom::bus.libretro_mem_map.size()};
+  core_bind.penviron(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, (void*)&map);
+  
+  if (SuperFamicom::cartridge.has_superfx())
+    superfx_freq_orig=SuperFamicom::superfx.frequency;
+  
+  return ret;
 }
 
+
 bool retro_load_game_special(unsigned game_type,
       const struct retro_game_info *info, size_t num_info) {
   core_bind.manifest = false;
@@ -898,7 +1017,7 @@
 }
 
 unsigned retro_get_region(void) {
-  return SuperFamicom::system.region() == SuperFamicom::System::Region::NTSC ? 0 : 1;
+  return SuperFamicom::system.region() == SuperFamicom::System::Region::NTSC ? RETRO_REGION_NTSC : RETRO_REGION_PAL;
 }
 
 void* retro_get_memory_data(unsigned id) {
@@ -942,7 +1061,7 @@
   switch(id) {
     case RETRO_MEMORY_SAVE_RAM:
       size = core_bind.sram_size;
-      fprintf(stderr, "[bsnes]: SRAM memory size: %u.\n", (unsigned)size);
+      output(RETRO_LOG_INFO, "SRAM memory size: %u.\n", (unsigned)size);
       break;
     case RETRO_MEMORY_RTC:
       size = 0;
