diff --git a/svn-current/trunk/src/burner/libretro/libretro.cpp b/svn-current/trunk/src/burner/libretro/libretro.cpp
index 639aab9..1b23498 100644
--- a/svn-current/trunk/src/burner/libretro/libretro.cpp
+++ b/svn-current/trunk/src/burner/libretro/libretro.cpp
@@ -153,6 +153,72 @@ void retro_set_environment(retro_environment_t cb)
    environ_cb = cb;
 }
 
+/* Frameskipping Support */
+
+unsigned frameskip_type             = 0;
+unsigned frameskip_threshold        = 0;
+uint16_t frameskip_counter          = 0;
+unsigned frameskip_interval         = 0;
+
+static bool retro_audio_buff_active        = false;
+static unsigned retro_audio_buff_occupancy = 0;
+static bool retro_audio_buff_underrun      = false;
+
+static unsigned audio_latency              = 0;
+static bool update_audio_latency           = false;
+
+static void retro_audio_buff_status_cb(
+      bool active, unsigned occupancy, bool underrun_likely)
+{
+   retro_audio_buff_active    = active;
+   retro_audio_buff_occupancy = occupancy;
+   retro_audio_buff_underrun  = underrun_likely;
+}
+
+void init_frameskip(void)
+{
+   if (frameskip_type > 0)
+   {
+      struct retro_audio_buffer_status_callback buf_status_cb;
+
+      buf_status_cb.callback = retro_audio_buff_status_cb;
+      if (!environ_cb(RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK,
+            &buf_status_cb))
+      {
+         if (log_cb)
+            log_cb(RETRO_LOG_WARN, "Frameskip disabled - frontend does not support audio buffer status monitoring.\n");
+
+         retro_audio_buff_active    = false;
+         retro_audio_buff_occupancy = 0;
+         retro_audio_buff_underrun  = false;
+         audio_latency              = 0;
+      }
+      else
+      {
+         /* Frameskip is enabled - increase frontend
+          * audio latency to minimise potential
+          * buffer underruns */
+#ifdef FBACORES_CPS
+         float frame_time_msec = 1000.0f / 59.629403f;
+#else
+         float frame_time_msec = 1000.0f / ((float)nBurnFPS / 100.0f);
+#endif
+         /* Set latency to 6x current frame time... */
+         audio_latency = (unsigned)((6.0f * frame_time_msec) + 0.5f);
+
+         /* ...then round up to nearest multiple of 32 */
+         audio_latency = (audio_latency + 0x1F) & ~0x1F;
+      }
+   }
+   else
+   {
+      environ_cb(RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK, NULL);
+      audio_latency = 0;
+   }
+
+   update_audio_latency = true;
+}
+
 char g_rom_dir[MAX_PATH];
 char g_save_dir[1024];
 char g_system_dir[1024];
@@ -789,6 +855,14 @@ void retro_init()
       log_cb = log_dummy;
 
    BurnLibInit();
+   frameskip_type             = 0;
+   frameskip_threshold        = 0;
+   frameskip_counter          = 0;
+   retro_audio_buff_active    = false;
+   retro_audio_buff_occupancy = 0;
+   retro_audio_buff_underrun  = false;
+   audio_latency              = 0;
+   update_audio_latency       = false;
 }
 
 void retro_deinit()
@@ -828,10 +902,50 @@ void retro_run()
 {
    int width, height;
    BurnDrvGetVisibleSize(&width, &height);
+   int nSkipFrame = 0;
+
    pBurnDraw = (uint8_t*)g_fba_frame;
 
    InputMake();
 
+   /* Check whether current frame should
+    * be skipped */
+   if ((frameskip_type > 0) && retro_audio_buff_active)
+   {
+      switch (frameskip_type)
+      {
+         case 1: /* auto */
+            nSkipFrame = retro_audio_buff_underrun ? 1 : 0;
+            break;
+         case 2: /* manual */
+            nSkipFrame = (retro_audio_buff_occupancy < frameskip_threshold) ? 1 : 0;
+            break;
+         default:
+            nSkipFrame = 0;
+            break;
+      }
+
+      if (!nSkipFrame || (frameskip_counter >= frameskip_interval))
+      {
+         nSkipFrame        = 0;
+         frameskip_counter = 0;
+      }
+      else
+         frameskip_counter++;
+   }
+
+   if (nSkipFrame)
+      pBurnDraw = NULL;
+
+   /* If frameskip settings have changed, update
+    * frontend audio latency */
+   if (update_audio_latency)
+   {
+      environ_cb(RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY,
+            &audio_latency);
+      update_audio_latency = false;
+   }
+
    ForceFrameStep();
 
    unsigned drv_flags = BurnDrvGetFlags();
@@ -851,7 +965,11 @@ void retro_run()
          nBurnPitch = width * pitch_size;
    }
 
-   video_cb(g_fba_frame, width, height, nBurnPitch);
+   if (!nSkipFrame)
+      video_cb(g_fba_frame, width, height, nBurnPitch);
+   else
+      video_cb(NULL, width, height, nBurnPitch);
+
    audio_batch_cb(g_audio_buf, nBurnSoundLen);
 
    bool updated = false;
@@ -860,7 +978,7 @@ void retro_run()
       neo_geo_modes old_g_opt_neo_geo_mode = g_opt_neo_geo_mode;
       bool old_bVerticalMode = bVerticalMode;
 
-      check_variables();
+      check_variables(false);
 
       apply_dipswitch_from_variables();
 
@@ -1166,7 +1284,7 @@ bool retro_load_game(const struct retro_game_info *info)
       SetControllerInfo();
 
       set_environment();
-      check_variables();
+      check_variables(true);
 
       pBurnSoundOut = g_audio_buf;
       nBurnSoundRate = AUDIO_SAMPLERATE;
diff --git a/svn-current/trunk/src/burner/libretro/retro_common.cpp b/svn-current/trunk/src/burner/libretro/retro_common.cpp
index 6b8bf31..95c994a 100644
--- a/svn-current/trunk/src/burner/libretro/retro_common.cpp
+++ b/svn-current/trunk/src/burner/libretro/retro_common.cpp
@@ -62,6 +62,11 @@ INT32 g_audio_samplerate = 48000;
 UINT8 *diag_input;
 neo_geo_modes g_opt_neo_geo_mode = NEO_GEO_MODE_MVS;
 
+extern unsigned frameskip_type;
+extern unsigned frameskip_threshold;
+extern uint16_t frameskip_counter;
+extern unsigned frameskip_interval;
+
 #ifdef USE_CYCLONE
 // 0 - c68k, 1 - m68k
 // we don't use cyclone by default because it breaks savestates cross-platform compatibility (including netplay)
@@ -78,9 +83,11 @@ static UINT8 diag_input_select_l_r[] =  {RETRO_DEVICE_ID_JOYPAD_SELECT, RETRO_DE
 
 // Global core options
 static const struct retro_variable var_empty = { NULL, NULL };
+static const struct retro_variable var_fbneo_frameskip = { "fbneo-frameskip-type", "Frameskip ; disabled|auto|threshold" };
+static const struct retro_variable var_fbneo_frameskip_threshold = { "fbneo-threshold", "FS Threshold (%) ; 30|40|50|60" };
+static const struct retro_variable var_fbneo_frameskip_interval = { "fbneo-interval", "FS Interval ; 0|1|2|3|4|5|6|7|8|9" };
 static const struct retro_variable var_fbneo_allow_depth_32 = { "fbneo-allow-depth-32", "Use 32-bits color depth when available; disabled|enabled" };
 static const struct retro_variable var_fbneo_vertical_mode = { "fbneo-vertical-mode", "Vertical mode; disabled|enabled" };
-static const struct retro_variable var_fbneo_frameskip = { "fbneo-frameskip", "Frameskip; 0|1|2|3|4|5" };
 static const struct retro_variable var_fbneo_cpu_speed_adjust = { "fbneo-cpu-speed-adjust", "CPU overclock; 100|110|120|130|140|150|160|170|180|190|200" };
 static const struct retro_variable var_fbneo_diagnostic_input = { "fbneo-diagnostic-input", "Diagnostic Input; None|Hold Start|Start + A + B|Hold Start + A + B|Start + L + R|Hold Start + L + R|Hold Select|Select + A + B|Hold Select + A + B|Select + L + R|Hold Select + L + R" };
 static const struct retro_variable var_fbneo_hiscores = { "fbneo-hiscores", "Hiscores; enabled|disabled" };
@@ -227,9 +234,11 @@ void set_environment()
 #endif
 
 	// Add the Global core options
+	vars_systems.push_back(&var_fbneo_frameskip);
+	vars_systems.push_back(&var_fbneo_frameskip_threshold);
+	vars_systems.push_back(&var_fbneo_frameskip_interval);
 	vars_systems.push_back(&var_fbneo_allow_depth_32);
 	vars_systems.push_back(&var_fbneo_vertical_mode);
-	vars_systems.push_back(&var_fbneo_frameskip);
 	vars_systems.push_back(&var_fbneo_cpu_speed_adjust);
 	vars_systems.push_back(&var_fbneo_hiscores);
 	if (nGameType != RETRO_GAME_TYPE_NEOCD)
@@ -304,9 +313,40 @@ void set_environment()
 #endif
 }
 
-void check_variables(void)
+void check_variables(bool first_run)
 {
 	struct retro_variable var = {0};
+	bool prev_frameskip_type;
+
+	var.key = var_fbneo_frameskip.key;
+	var.value = NULL;
+
+	prev_frameskip_type = frameskip_type;
+	frameskip_type      = 0;
+
+	if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+	{
+		if (strcmp(var.value, "auto") == 0)
+			frameskip_type = 1;
+		if (strcmp(var.value, "threshold") == 0)
+			frameskip_type = 2;
+	}
+
+	var.key = var_fbneo_frameskip_threshold.key;
+	var.value = NULL;
+
+	frameskip_threshold = 30;
+
+	if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+		frameskip_threshold = strtol(var.value, NULL, 10);
+
+	var.key = var_fbneo_frameskip_interval.key;
+	var.value = NULL;
+
+	frameskip_interval = 1;
+
+	if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+		frameskip_interval = strtol(var.value, NULL, 10);
 
 	var.key = var_fbneo_cpu_speed_adjust.key;
 	if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
@@ -542,6 +582,11 @@ void check_variables(void)
 			bCycloneEnabled = false;
 	}
 #endif
+
+	/* Reinitialise frameskipping, if required */
+	if (!first_run &&
+	    ((frameskip_type     != prev_frameskip_type)))
+		init_frameskip();
 }
 
 #ifdef USE_CYCLONE
diff --git a/svn-current/trunk/src/burner/libretro/retro_common.h b/svn-current/trunk/src/burner/libretro/retro_common.h
index 3efc786..f4feae6 100644
--- a/svn-current/trunk/src/burner/libretro/retro_common.h
+++ b/svn-current/trunk/src/burner/libretro/retro_common.h
@@ -78,7 +78,8 @@ char* str_char_replace(char* destination, char c_find, char c_replace);
 void set_neo_system_bios();
 void evaluate_neogeo_bios_mode(const char* drvname);
 void set_environment();
-void check_variables(void);
+void check_variables(bool first_run);
+void init_frameskip();
 #ifdef USE_CYCLONE
 void SetSekCpuCore();
 #endif
diff --git a/svn-current/trunk/src/burner/libretro/retro_input.cpp b/svn-current/trunk/src/burner/libretro/retro_input.cpp
index d6b1980..2bf2e8d 100644
--- a/svn-current/trunk/src/burner/libretro/retro_input.cpp
+++ b/svn-current/trunk/src/burner/libretro/retro_input.cpp
@@ -2293,7 +2293,7 @@ void InputInit()
 	// Update core option for diagnostic inputs
 	set_environment();
 	// Read the user core option values
-	check_variables();
+	check_variables(false);
 
 	// The list of input descriptors is filled, we can assign them to retroarch
 	//SetInputDescriptors();
