diff --git a/apu/apu.cpp b/apu/apu.cpp
index 4b7c6dc5..34460b20 100644
--- a/apu/apu.cpp
+++ b/apu/apu.cpp
@@ -190,6 +190,7 @@
 #include <math.h>
 #include "snes9x.h"
 #include "apu.h"
+#include "msu1.h"
 #include "snapshot.h"
 #include "display.h"
 #include "hermite_resampler.h"
@@ -239,6 +240,13 @@ namespace spc
 	static uint32		ratio_denominator = APU_DENOMINATOR_NTSC;
 }
 
+namespace msu
+{
+	static int			buffer_size;
+	static uint8		*landing_buffer = NULL;
+	static Resampler	*resampler		= NULL;
+}
+
 static void EightBitize (uint8 *, int);
 static void DeStereo (uint8 *, int);
 static void ReverseStereo (uint8 *, int);
@@ -311,6 +319,9 @@ bool8 S9xMixSamples (uint8 *buffer, int sample_count)
 		memset(dest, 0, sample_count << 1);
 		spc::resampler->clear();
 
+		if(Settings.MSU1)
+			msu::resampler->clear();
+
 		return (FALSE);
 	}
 	else
@@ -320,6 +331,17 @@ bool8 S9xMixSamples (uint8 *buffer, int sample_count)
 			spc::resampler->read((short *) dest, sample_count);
 			if (spc::lag == spc::lag_master)
 				spc::lag = 0;
+
+			if (Settings.MSU1)
+			{
+				if (msu::resampler->avail() >= sample_count)
+				{
+					uint8 *msu_sample = new uint8[sample_count * 2];
+					msu::resampler->read((short *)msu_sample, sample_count);
+					for (uint32 i = 0; i < sample_count; ++i)
+						*((int16*)(dest+(i * 2))) += *((int16*)(msu_sample+(i * 2)));
+				}
+			}
 		}
 		else
 		{
@@ -361,7 +383,19 @@ void S9xFinalizeSamples (void)
 {
 	if (!Settings.Mute)
 	{
-		if (!spc::resampler->push((short *) spc::landing_buffer, SNES::dsp.spc_dsp.sample_count ()))
+		if (Settings.MSU1)
+		{
+			S9xMSU1Generate(SNES::dsp.spc_dsp.sample_count());
+			if (!msu::resampler->push((short *)msu::landing_buffer, S9xMSU1Samples()))
+			{
+				//spc::sound_in_sync = FALSE;
+
+				//if (Settings.SoundSync && !Settings.TurboMode)
+					//return;
+			}
+		}
+
+		if (!spc::resampler->push((short *)spc::landing_buffer, SNES::dsp.spc_dsp.sample_count()))
 		{
 			/* We weren't able to process the entire buffer. Potential overrun. */
 			spc::sound_in_sync = FALSE;
@@ -371,6 +405,7 @@ void S9xFinalizeSamples (void)
 		}
 	}
 
+
 	if (!Settings.SoundSync || Settings.TurboMode || Settings.Mute)
 		spc::sound_in_sync = TRUE;
 	else
@@ -380,6 +415,9 @@ void S9xFinalizeSamples (void)
 		spc::sound_in_sync = FALSE;
 
 	SNES::dsp.spc_dsp.set_output((SNES::SPC_DSP::sample_t *) spc::landing_buffer, spc::buffer_size);
+
+	if (Settings.MSU1)
+		S9xMSU1SetOutput((int16 *)msu::landing_buffer, msu::buffer_size);
 }
 
 void S9xLandSamples (void)
@@ -393,6 +431,8 @@ void S9xLandSamples (void)
 void S9xClearSamples (void)
 {
 	spc::resampler->clear();
+	if (Settings.MSU1)
+		msu::resampler->clear();
 	spc::lag = spc::lag_master;
 }
 
@@ -419,6 +459,12 @@ static void UpdatePlaybackRate (void)
 
 	double time_ratio = (double) Settings.SoundInputRate * spc::timing_hack_numerator / (Settings.SoundPlaybackRate * spc::timing_hack_denominator);
 	spc::resampler->time_ratio(time_ratio);
+
+	if (Settings.MSU1)
+	{
+		time_ratio = (44100.0 / Settings.SoundPlaybackRate) * (Settings.SoundInputRate / 32040);
+		msu::resampler->time_ratio(time_ratio);
+	}
 }
 
 bool8 S9xInitSound (int buffer_ms, int lag_ms)
@@ -426,8 +472,8 @@ bool8 S9xInitSound (int buffer_ms, int lag_ms)
 	// buffer_ms : buffer size given in millisecond
 	// lag_ms    : allowable time-lag given in millisecond
 
-	int	sample_count     = buffer_ms * 32000 / 1000;
-	int	lag_sample_count = lag_ms    * 32000 / 1000;
+	int	sample_count     = buffer_ms * 32040 / 1000;
+	int	lag_sample_count = lag_ms    * 32040 / 1000;
 
 	spc::lag_master = lag_sample_count;
 	if (Settings.Stereo)
@@ -442,6 +488,7 @@ bool8 S9xInitSound (int buffer_ms, int lag_ms)
 		spc::buffer_size <<= 1;
 	if (Settings.SixteenBitSound)
 		spc::buffer_size <<= 1;
+	msu::buffer_size = ((buffer_ms * 44100 / 1000) * 44100 / 32040) << 2; // Always 16-bit, Stereo
 
 	printf("Sound buffer size: %d (%d samples)\n", spc::buffer_size, sample_count);
 
@@ -450,6 +497,11 @@ bool8 S9xInitSound (int buffer_ms, int lag_ms)
 	spc::landing_buffer = new uint8[spc::buffer_size * 2];
 	if (!spc::landing_buffer)
 		return (FALSE);
+	if (msu::landing_buffer)
+		delete[] msu::landing_buffer;
+	msu::landing_buffer = new uint8[msu::buffer_size * 2];
+	if (!msu::landing_buffer)
+		return (FALSE);
 
 	/* The resampler and spc unit use samples (16-bit short) as
 	   arguments. Use 2x in the resampler for buffer leveling with SoundSync */
@@ -465,6 +517,20 @@ bool8 S9xInitSound (int buffer_ms, int lag_ms)
 	else
 		spc::resampler->resize(spc::buffer_size >> (Settings.SoundSync ? 0 : 1));
 
+
+	if (!msu::resampler)
+	{
+		msu::resampler = new HermiteResampler(msu::buffer_size);
+		if (!msu::resampler)
+		{
+			delete[] msu::landing_buffer;
+			return (FALSE);
+		}
+	}
+	else
+		msu::resampler->resize(msu::buffer_size);
+
+
 	SNES::dsp.spc_dsp.set_output ((SNES::SPC_DSP::sample_t *) spc::landing_buffer, spc::buffer_size);
 
 	UpdatePlaybackRate();
@@ -503,6 +569,7 @@ bool8 S9xInitAPU (void)
 	spc::landing_buffer = NULL;
 	spc::shrink_buffer  = NULL;
 	spc::resampler      = NULL;
+	msu::resampler		= NULL;
 
 	return (TRUE);
 }
@@ -526,6 +593,18 @@ void S9xDeinitAPU (void)
 		delete[] spc::shrink_buffer;
 		spc::shrink_buffer = NULL;
 	}
+
+	if (msu::resampler)
+	{
+		delete msu::resampler;
+		msu::resampler = NULL;
+	}
+
+	if (msu::landing_buffer)
+	{
+		delete[] msu::landing_buffer;
+		msu::landing_buffer = NULL;
+	}
 }
 
 static inline int S9xAPUGetClock (int32 cpucycles)
@@ -603,6 +682,9 @@ void S9xResetAPU (void)
 	SNES::dsp.spc_dsp.set_spc_snapshot_callback(SPCSnapshotCallback);
 
 	spc::resampler->clear();
+
+	if (Settings.MSU1)
+		msu::resampler->clear();
 }
 
 void S9xSoftResetAPU (void)
@@ -615,6 +697,9 @@ void S9xSoftResetAPU (void)
 	SNES::dsp.spc_dsp.set_output ((SNES::SPC_DSP::sample_t *) spc::landing_buffer, spc::buffer_size >> 1);
 
 	spc::resampler->clear();
+
+	if (Settings.MSU1)
+		msu::resampler->clear();
 }
 
 void S9xAPUSaveState (uint8 *block)
diff --git a/apu/hermite_resampler.h b/apu/hermite_resampler.h
index 8c7dd96b..ea526ef1 100644
--- a/apu/hermite_resampler.h
+++ b/apu/hermite_resampler.h
@@ -4,6 +4,7 @@
 #define __HERMITE_RESAMPLER_H
 
 #include "resampler.h"
+#include <assert.h>
 
 #undef CLAMP
 #undef SHORT_CLAMP
@@ -66,6 +67,7 @@ class HermiteResampler : public Resampler
         void
         read (short *data, int num_samples)
         {
+            assert((num_samples & 1) == 0); // resampler always processes both stereo samples
             int i_position = start >> 1;
             int max_samples = buffer_size >> 1;
             short *internal_buffer = (short *) buffer;
diff --git a/bsx.cpp b/bsx.cpp
index c317bd26..2b4454e3 100644
--- a/bsx.cpp
+++ b/bsx.cpp
@@ -199,7 +199,7 @@
 //#define BSX_DEBUG
 
 #define BIOS_SIZE	0x100000
-#define FLASH_SIZE	0x200000
+#define FLASH_SIZE	0x100000
 #define PSRAM_SIZE	0x80000
 
 #define Map			Memory.Map
@@ -231,7 +231,7 @@ static const uint8	flashcard[20] =
 {
 	0x4D, 0x00, 0x50, 0x00,	// vendor id
 	0x00, 0x00,				// ?
-	0x2B, 0x00,				// 2MB Flash (1MB = 0x2A)
+	0x1A, 0x00,				// 2MB Flash (1MB = 0x2A)
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
@@ -417,13 +417,22 @@ static void map_psram_mirror_sub (uint32 bank)
 	{
 		for (c = 0; c < 0x100; c += 16)
 		{
-			for (i = c; i < c + 8; i++)
-				Map[i + bank] = &PSRAM[(c << 11) % PSRAM_SIZE];
+			if ((bank & 0x7F) >= 0x40)
+			{
+				for (i = c; i < c + 8; i++)
+					Map[i + bank] = &PSRAM[(c << 11) % PSRAM_SIZE];
+
+				for (i = c; i < c + 8; i++)
+				{
+					BlockIsRAM[i + bank] = TRUE;
+					BlockIsROM[i + bank] = FALSE;
+				}
+			}
 
 			for (i = c + 8; i < c + 16; i++)
 				Map[i + bank] = &PSRAM[(c << 11) % PSRAM_SIZE] - 0x8000;
 
-			for (i = c; i < c + 16; i++)
+			for (i = c + 8; i < c + 16; i++)
 			{
 				BlockIsRAM[i + bank] = TRUE;
 				BlockIsROM[i + bank] = FALSE;
@@ -432,42 +441,126 @@ static void map_psram_mirror_sub (uint32 bank)
 	}
 }
 
-static void BSX_Map_PSRAM (void)
+static void BSX_Map_PSRAM(void)
 {
-	int	c;
+	int	c, i;
 
-	// Banks 70->77:0000-FFFF
-	// FIXME: could be toggled by $03
-	for (c = 0; c < 0x80; c++)
+	if (!BSX.MMC[0x02])
 	{
-		Map[c + 0x700] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE];
-		BlockIsRAM[c + 0x700] = TRUE;
-		BlockIsROM[c + 0x700] = FALSE;
-	}
+		//LoROM Mode
+		if (!BSX.MMC[0x05] && !BSX.MMC[0x06])
+		{
+			//Map PSRAM to 00-0F/80-8F
+			if (BSX.MMC[0x03])
+				map_psram_mirror_sub(0x00);
 
-	// Banks 20->3F:6000-7FFF mirrors 70->77:6000-7FFF
-	for (c = 0x200; c < 0x400; c += 16)
+			if (BSX.MMC[0x04])
+				map_psram_mirror_sub(0x80);
+		}
+		else if (BSX.MMC[0x05] && !BSX.MMC[0x06])
+		{
+			//Map PSRAM to 20-2F/A0-AF
+			if (BSX.MMC[0x03])
+				map_psram_mirror_sub(0x20);
+
+			if (BSX.MMC[0x04])
+				map_psram_mirror_sub(0xA0);
+		}
+		else if (!BSX.MMC[0x05] && BSX.MMC[0x06])
+		{
+			//Map PSRAM to 40-4F/C0-CF
+			if (BSX.MMC[0x03])
+				map_psram_mirror_sub(0x40);
+
+			if (BSX.MMC[0x04])
+				map_psram_mirror_sub(0xC0);
+		}
+		else
+		{
+			//Map PSRAM to 60-6F/E0-EF
+			if (BSX.MMC[0x03])
+				map_psram_mirror_sub(0x60);
+
+			if (BSX.MMC[0x04])
+				map_psram_mirror_sub(0xE0);
+		}
+
+		//Map PSRAM to 70-7D/F0-FF
+		if (BSX.MMC[0x03])
+			map_psram_mirror_sub(0x70);
+
+		if (BSX.MMC[0x04])
+			map_psram_mirror_sub(0xF0);
+	}
+	else
 	{
-		Map[c + 6] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE];
-		Map[c + 7] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE];
-		BlockIsRAM[c + 6] = TRUE;
-		BlockIsRAM[c + 7] = TRUE;
-		BlockIsROM[c + 6] = FALSE;
-		BlockIsROM[c + 7] = FALSE;
+		//HiROM Mode
+		if (!BSX.MMC[0x05] && !BSX.MMC[0x06])
+		{
+			//Map PSRAM to 40-47/C0-C7
+			if (BSX.MMC[0x03])
+				map_psram_mirror_sub(0x40);
+
+			if (BSX.MMC[0x04])
+				map_psram_mirror_sub(0xC0);
+
+		}
+		else if (BSX.MMC[0x05] && !BSX.MMC[0x06])
+		{
+			//Map PSRAM to 50-57/D0-D7
+			if (BSX.MMC[0x03])
+				map_psram_mirror_sub(0x50);
+
+			if (BSX.MMC[0x04])
+				map_psram_mirror_sub(0xD0);
+		}
+		else if (!BSX.MMC[0x05] && BSX.MMC[0x06])
+		{
+			//Map PSRAM to 60-67/E0-E7
+			if (BSX.MMC[0x03])
+				map_psram_mirror_sub(0x60);
+
+			if (BSX.MMC[0x04])
+				map_psram_mirror_sub(0xE0);
+		}
+		else
+		{
+			//Map PSRAM to 70-77/F0-F7
+			if (BSX.MMC[0x03])
+				map_psram_mirror_sub(0x70);
+
+			if (BSX.MMC[0x04])
+				map_psram_mirror_sub(0xF0);
+		}
+
+		if (BSX.MMC[0x03])
+		{
+			//Map PSRAM to 20->3F:6000-7FFF
+			for (c = 0x200; c < 0x400; c += 16)
+			{
+				Map[c + 6] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE];
+				Map[c + 7] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE];
+				BlockIsRAM[c + 6] = TRUE;
+				BlockIsRAM[c + 7] = TRUE;
+				BlockIsROM[c + 6] = FALSE;
+				BlockIsROM[c + 7] = FALSE;
+			}
+		}
+
+		if (BSX.MMC[0x04])
+		{
+			//Map PSRAM to A0->BF:6000-7FFF
+			for (c = 0xA00; c < 0xC00; c += 16)
+			{
+				Map[c + 6] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE];
+				Map[c + 7] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE];
+				BlockIsRAM[c + 6] = TRUE;
+				BlockIsRAM[c + 7] = TRUE;
+				BlockIsROM[c + 6] = FALSE;
+				BlockIsROM[c + 7] = FALSE;
+			}
+		}
 	}
-
-	if (!BSX.MMC[0x05])
-		// Banks 40->4F:0000-FFFF mirrors 70->77:0000-7FFF
-		map_psram_mirror_sub(0x40);
-
-	if (!BSX.MMC[0x06])
-		// Banks 50->5F:0000-FFFF mirrors 70->77:0000-7FFF
-		map_psram_mirror_sub(0x50);
-
-	// FIXME
-	if (!BSX.MMC[0x03])
-		// Banks 60->6F:0000-FFFF mirrors 70->77:0000-7FFF (?)
-		map_psram_mirror_sub(0x60);
 }
 
 static void BSX_Map_BIOS (void)
@@ -562,28 +655,8 @@ static void BSX_Map (void)
 
 	memcpy(BSX.prevMMC, BSX.MMC, sizeof(BSX.MMC));
 
-	// Do a quick bank change
-	if (BSX.dirty2 && !BSX.dirty)
-	{
-		BSX_Map_Dirty();
-		BSX_Map_BIOS();
-
-		BSX.dirty2 = FALSE;
-
-		Memory.map_WriteProtectROM();
-		return;
-	}
-
-	if (BSX.MMC[0x01])
-	{
-		MapROM = PSRAM;
-		FlashSize = PSRAM_SIZE;
-	}
-	else
-	{
-		MapROM = FlashROM;
-		FlashSize = FLASH_SIZE;
-	}
+	MapROM = FlashROM;
+	FlashSize = FLASH_SIZE;
 
 	BSX_Map_SNES();
 
@@ -592,12 +665,12 @@ static void BSX_Map (void)
 	else
 		BSX_Map_LoROM();
 
+	BSX_Map_FlashIO();
 	BSX_Map_PSRAM();
 	BSX_Map_SRAM();
 	BSX_Map_RAM();
 
 	BSX_Map_BIOS();
-	BSX_Map_FlashIO();
 	BSX_Map_MMC();
 
 	// Monitor new register changes
@@ -607,30 +680,24 @@ static void BSX_Map (void)
 	Memory.map_WriteProtectROM();
 }
 
-static uint8 BSX_Get_Bypass_FlashIO (uint16 offset)
+static uint8 BSX_Get_Bypass_FlashIO (uint32 offset)
 {
+	MapROM = FlashROM = Memory.ROM + Multi.cartOffsetB;
+
 	if (BSX.MMC[0x02])
-		return (MapROM[offset]);
+		return (MapROM[offset & 0x0FFFFF]);
 	else
-	{
-		if (offset < 0x8000)
-			return (MapROM[offset]);
-		else
-			return (MapROM[offset - 0x8000]);
-	}
+		return (MapROM[(offset & 0x1F0000) >> 1 | (offset & 0x7FFF)]);
 }
 
-static void BSX_Set_Bypass_FlashIO (uint16 offset, uint8 byte)
+static void BSX_Set_Bypass_FlashIO (uint32 offset, uint8 byte)
 {
+	MapROM = FlashROM = Memory.ROM + Multi.cartOffsetB;
+
 	if (BSX.MMC[0x02])
-		MapROM[offset] = byte;
+		MapROM[offset & 0x0FFFFF] = MapROM[offset & 0x0FFFFF] & byte;
 	else
-	{
-		if (offset < 0x8000)
-			MapROM[offset] = byte;
-		else
-			MapROM[offset - 0x8000] = byte;
-	}
+		MapROM[(offset & 0x1F0000) >> 1 | (offset & 0x7FFF)] = MapROM[(offset & 0x1F0000) >> 1 | (offset & 0x7FFF)] & byte;
 }
 
 uint8 S9xGetBSX (uint32 address)
@@ -640,43 +707,57 @@ uint8 S9xGetBSX (uint32 address)
 	uint8	t = 0;
 
 	// MMC
-	if ((bank >= 0x01 && bank <= 0x0E) && (offset == 0x5000))
+	if ((bank >= 0x01 && bank <= 0x0E))
 		return (BSX.MMC[bank]);
 
 	// Flash IO
-	if (bank == 0xC0)
+	if (bank >= 0xC0)
 	{
 		// default: read-through mode
-		t = BSX_Get_Bypass_FlashIO(offset);
+		t = BSX_Get_Bypass_FlashIO(address);
 
 		// note: may be more registers, purposes unknown
 		switch (offset)
 		{
-			case 0x0002:
-				if (BSX.flash_enable)
-					t = 0x80; // status register?
-				break;
+		case 0x0002:
+		case 0x8002:
+			if (BSX.flash_bsr)
+				t = 0xC0; // Page Status Register
+			break;
 
-			case 0x5555:
-				if (BSX.flash_enable)
-					t = 0x80; // ???
-				break;
+		case 0x0004:
+		case 0x8004:
+			if (BSX.flash_gsr)
+				t = 0x82; // Global Status Register
+			break;
 
-			case 0xFF00:
-			case 0xFF02:
-			case 0xFF04:
-			case 0xFF06:
-			case 0xFF08:
-			case 0xFF0A:
-			case 0xFF0C:
-			case 0xFF0E:
-			case 0xFF10:
-			case 0xFF12:
-				// return flash vendor information
-				if (BSX.read_enable)
-					t = flashcard[offset - 0xFF00];
-				break;
+		case 0x5555:
+			if (BSX.flash_enable)
+				t = 0x80; // ???
+			break;
+
+		case 0xFF00:
+		case 0xFF02:
+		case 0xFF04:
+		case 0xFF06:
+		case 0xFF08:
+		case 0xFF0A:
+		case 0xFF0C:
+		case 0xFF0E:
+		case 0xFF10:
+		case 0xFF12:
+			// return flash vendor information
+			if (BSX.read_enable)
+				t = flashcard[offset - 0xFF00];
+			break;
 		}
+
+		if (BSX.flash_csr)
+		{
+			t = 0x80; // Compatible Status Register
+			BSX.flash_csr = false;
+		}
+
 	}
 
 	return (t);
@@ -688,115 +769,126 @@ void S9xSetBSX (uint8 byte, uint32 address)
 	uint16	offset = address & 0xFFFF;
 
 	// MMC
-	if ((bank >= 0x01 && bank <= 0x0E) && (offset == 0x5000))
+	if ((bank >= 0x01 && bank <= 0x0E))
 	{
-		switch (bank)
-		{
-			case 0x01:
-			case 0x02:
-			case 0x03:
-			case 0x04:
-			case 0x05:
-			case 0x06:
-			case 0x09:
-			case 0x0A:
-			case 0x0B:
-			case 0x0C:
-			case 0x0D:
-				if (BSX.MMC[bank] != byte)
-				{
-					BSX.MMC[bank] = byte;
-					BSX.dirty = TRUE;
-				}
-				break;
-
-			case 0x07:
-			case 0x08:
-				if (BSX.MMC[bank] != byte)
-				{
-					BSX.MMC[bank] = byte;
-					BSX.dirty2 = TRUE;
-				}
-				break;
-
-			case 0x0E:
-				BSX.MMC[bank] = byte;
-				if (byte && (BSX.dirty || BSX.dirty2))
-					BSX_Map();
-				break;
-		}
+		BSX.MMC[bank] = byte;
+		if (bank == 0x0E)
+			BSX_Map();
 	}
 
 	// Flash IO
-	if (bank == 0xC0)
+	if (bank >= 0xC0)
 	{
-		BSX.old_write = BSX.new_write;
-		BSX.new_write = address;
-
-		// ???: double writes to the desired address will bypass
-		// flash registers
-		if (BSX.old_write == BSX.new_write && BSX.write_enable)
+		// Write to Flash
+		if (BSX.write_enable)
 		{
-			BSX_Set_Bypass_FlashIO(offset, byte);
+			BSX_Set_Bypass_FlashIO(address, byte);
+			//MapROM[address & 0x3FFFFF] = byte;
+			BSX.write_enable = false;
 			return;
 		}
 
-		// flash command handling
-		// note: incomplete
-		switch (offset)
-		{
-			case 0x0000:
-				BSX.flash_command <<= 8;
-				BSX.flash_command |= byte;
-				if ((BSX.flash_command & 0xFFFF) == 0x38D0)
-				{
-					// retrieve information about the flash card
-					BSX.flash_enable = TRUE;
-					BSX.read_enable  = TRUE;
-				}
-				break;
+		// Flash Command Handling
+		if (BSX.MMC[0xC]) {
+			//Memory Pack Type 1 & 3 & 4
+			BSX.flash_command <<= 8;
+			BSX.flash_command |= byte;
 
-			case 0x2AAA:
-				BSX.flash_command <<= 8;
-				BSX.flash_command |= byte;
-				break;
+			switch (BSX.flash_command & 0xFF)
+			{
+				case 0x00:
+				case 0xFF:
+					//Reset to normal
+					BSX.flash_enable = false;
+					BSX.flash_bsr = false;
+					BSX.flash_csr = false;
+					BSX.flash_gsr = false;
+					BSX.read_enable = false;
+					BSX.write_enable = false;
+					BSX.flash_cmd_done = true;
+					break;
 
-			case 0x5555:
-				BSX.flash_command <<= 8;
-				BSX.flash_command |= byte;
+				case 0x10:
+				case 0x40:
+					//Write Byte
+					BSX.flash_enable = false;
+					BSX.flash_bsr = false;
+					BSX.flash_csr = true;
+					BSX.flash_gsr = false;
+					BSX.read_enable = false;
+					BSX.write_enable = true;
+					BSX.flash_cmd_done = true;
+					break;
 
-				switch (BSX.flash_command & 0xFFFFFF)
-				{
-					case 0xAA55F0:
-						// turn off flash i/o
-						BSX.flash_enable = FALSE;
-						BSX.write_enable = FALSE;
-						BSX.read_enable  = FALSE;
-						break;
+				case 0x50:
+					//Clear Status Register
+					BSX.flash_enable = false;
+					BSX.flash_bsr = false;
+					BSX.flash_csr = false;
+					BSX.flash_gsr = false;
+					BSX.flash_cmd_done = true;
+					break;
 
-					case 0xAA55A0:
-						// enable writing to flash
-						BSX.old_write = 0;
-						BSX.new_write = 0;
-						BSX.flash_enable = TRUE;
-						BSX.write_enable = TRUE;
-						BSX_Map();
-						break;
+				case 0x70:
+					//Read CSR
+					BSX.flash_enable = false;
+					BSX.flash_bsr = false;
+					BSX.flash_csr = true;
+					BSX.flash_gsr = false;
+					BSX.read_enable = false;
+					BSX.write_enable = false;
+					BSX.flash_cmd_done = true;
+					break;
 
-					case 0xAA5570:
-						// turn on write-protection
-						BSX.write_enable = FALSE;
-						BSX_Map();
-						break;
+				case 0x71:
+					//Read Extended Status Registers (Page and Global)
+					BSX.flash_enable = false;
+					BSX.flash_bsr = true;
+					BSX.flash_csr = false;
+					BSX.flash_gsr = true;
+					BSX.read_enable = false;
+					BSX.write_enable = false;
+					BSX.flash_cmd_done = true;
+					break;
 
-					case 0xAA5580:
-					case 0xAA5510:
-						// ???
-						break;
+				case 0x75:
+					//Show Page Buffer / Vendor Info
+					BSX.flash_csr = false;
+					BSX.read_enable = true;
+					BSX.flash_cmd_done = true;
+					break;
 
-				}
+				case 0xD0:
+					//DO COMMAND
+					switch (BSX.flash_command & 0xFFFF)
+					{
+						case 0x20D0: //Block Erase
+							uint32 x;
+							for (x = 0; x < 0x10000; x++) {
+								//BSX_Set_Bypass_FlashIO(((address & 0xFF0000) + x), 0xFF);
+								if (BSX.MMC[0x02])
+									MapROM[(address & 0x0F0000) + x] = 0xFF;
+								else
+									MapROM[((address & 0x1E0000) >> 1) + x] = 0xFF;
+							}
+							break;
 
-				break;
+						case 0xA7D0: //Chip Erase (ONLY IN TYPE 1 AND 4)
+							if ((flashcard[6] & 0xF0) == 0x10 || (flashcard[6] & 0xF0) == 0x40)
+							{
+								uint32 x;
+								for (x = 0; x < FLASH_SIZE; x++) {
+									//BSX_Set_Bypass_FlashIO(x, 0xFF);
+									MapROM[x] = 0xFF;
+								}
+							}
+							break;
+
+						case 0x38D0: //Flashcart Reset
+							break;
+					}
+					break;
+			}
 		}
 	}
 }
@@ -1082,7 +1174,7 @@ void S9xInitBSX (void)
 			uint8	*header = r1 ? Memory.ROM + 0x7FC0 : Memory.ROM + 0xFFC0;
 
 			FlashMode = (header[0x18] & 0xEF) == 0x20 ? FALSE : TRUE;
-			FlashSize = (header[0x19] & 0x20) ? PSRAM_SIZE : FLASH_SIZE;
+			FlashSize = FLASH_SIZE;
 
 #ifdef BSX_DEBUG
 			for (int i = 0; i <= 0x1F; i++)
@@ -1145,32 +1237,11 @@ void S9xResetBSX (void)
 	memset(BSX.output, 0, sizeof(BSX.output));
 
 	// starting from the bios
-	if (BSX.bootup)
-		BSX.MMC[0x07] = BSX.MMC[0x08] = 0x80;
-	else
-	{
-		BSX.MMC[0x02] = FlashMode ? 0x80: 0;
+	BSX.MMC[0x02] = BSX.MMC[0x03] = BSX.MMC[0x05] = BSX.MMC[0x06] = 0x80;
+	BSX.MMC[0x09] = BSX.MMC[0x0B] = 0x80;
 
-		// per bios: run from psram or flash card
-		if (FlashSize == PSRAM_SIZE)
-		{
-			memcpy(PSRAM, FlashROM, PSRAM_SIZE);
-
-			BSX.MMC[0x01] = 0x80;
-			BSX.MMC[0x03] = 0x80;
-			BSX.MMC[0x04] = 0x80;
-			BSX.MMC[0x0C] = 0x80;
-			BSX.MMC[0x0D] = 0x80;
-		}
-		else
-		{
-			BSX.MMC[0x03] = 0x80;
-			BSX.MMC[0x05] = 0x80;
-			BSX.MMC[0x06] = 0x80;
-		}
-
-		BSX.MMC[0x0E] = 0x80;
-	}
+	BSX.MMC[0x07] = BSX.MMC[0x08] = 0x80;
+	BSX.MMC[0x0E] = 0x80;
 
 	BSX_Map();
 }
diff --git a/bsx.h b/bsx.h
index 5d5ea03d..ac5a2906 100644
--- a/bsx.h
+++ b/bsx.h
@@ -208,6 +208,11 @@ struct SBSX
 	uint8	MMC[16];
 	uint8	prevMMC[16];
 	uint8	test2192[32];
+
+	bool	flash_csr;
+	bool	flash_gsr;
+	bool	flash_bsr;
+	bool	flash_cmd_done;
 };
 
 extern struct SBSX	BSX;
diff --git a/conffile.h b/conffile.h
index ed8a13b4..366706fa 100644
--- a/conffile.h
+++ b/conffile.h
@@ -197,7 +197,11 @@
 #include <string>
 
 #ifdef UNZIP_SUPPORT
-#include "unzip/unzip.h"
+#  ifdef SYSTEM_ZIP
+#    include <minizip/unzip.h>
+#  else
+#    include "unzip/unzip.h"
+#  endif
 #endif
 #include "snes9x.h"
 
diff --git a/cpu.cpp b/cpu.cpp
index 545cd116..474fba8a 100644
--- a/cpu.cpp
+++ b/cpu.cpp
@@ -295,6 +295,7 @@ void S9xReset (void)
 	S9xResetPPU();
 	S9xResetDMA();
 	S9xResetAPU();
+    S9xResetMSU();
 
 	if (Settings.DSP)
 		S9xResetDSP();
@@ -312,6 +313,8 @@ void S9xReset (void)
 		S9xResetOBC1();
 	if (Settings.SRTC)
 		S9xResetSRTC();
+	if (Settings.MSU1)
+		S9xMSU1Init();
 
 	S9xInitCheatData();
 }
@@ -329,6 +332,7 @@ void S9xSoftReset (void)
 	S9xSoftResetPPU();
 	S9xResetDMA();
 	S9xSoftResetAPU();
+    S9xResetMSU();
 
 	if (Settings.DSP)
 		S9xResetDSP();
@@ -346,6 +350,8 @@ void S9xSoftReset (void)
 		S9xResetOBC1();
 	if (Settings.SRTC)
 		S9xResetSRTC();
+	if (Settings.MSU1)
+		S9xMSU1Init();
 
 	S9xInitCheatData();
 }
diff --git a/getset.h b/getset.h
index f72be543..747b5630 100644
--- a/getset.h
+++ b/getset.h
@@ -199,6 +199,7 @@
 #include "obc1.h"
 #include "seta.h"
 #include "bsx.h"
+#include "msu1.h"
 
 #define addCyclesInMemoryAccess \
 	if (!CPU.InDMAorHDMA) \
diff --git a/globals.cpp b/globals.cpp
index f9e18888..25afc1c9 100644
--- a/globals.cpp
+++ b/globals.cpp
@@ -232,6 +232,7 @@ struct SSPC7110Snapshot	s7snap;
 struct SSRTCSnapshot	srtcsnap;
 struct SRTCData			RTCData;
 struct SBSX				BSX;
+struct SMSU1			MSU1;
 struct SMulti			Multi;
 struct SSettings		Settings;
 struct SSNESGameFixes	SNESGameFixes;
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index fad1cf22..54fb3e59 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -136,6 +136,11 @@ snes9x_gtk_SOURCES += \
     ../apu/bapu/smp/smp.cpp \
     ../apu/bapu/smp/smp_state.cpp
 
+# MSU1
+snes9x_gtk_SOURCES += \
+    ../msu1.cpp \
+    ../msu1.h
+
 # DSP
 snes9x_gtk_SOURCES += \
     ../dsp.cpp \
@@ -196,12 +201,16 @@ snes9x_gtk_SOURCES += \
     ../server.cpp
 endif
 
+
 # Zip support is nonconfigurable.
 snes9x_gtk_SOURCES += \
-    ../loadzip.cpp \
+    ../loadzip.cpp
+if ! SYSTEM_ZIP
+snes9x_gtk_SOURCES += \
     ../unzip/unzip.c \
     ../unzip/ioapi.c \
     ../unzip/zip.c
+endif
 UNZIPDEFINES=-DUNZIP_SUPPORT
 
 if JMA
diff --git a/gtk/configure.ac b/gtk/configure.ac
index 4d21792a..50f204f3 100644
--- a/gtk/configure.ac
+++ b/gtk/configure.ac
@@ -138,6 +138,12 @@ AC_ARG_WITH(zlib,
   [],
   [with_zlib=yes])
 
+AC_ARG_WITH(system-zip,
+  [AS_HELP_STRING([--with(out)-system-zip],
+    [Use system zip])],
+  [],
+  [system_zip=check])
+
 AC_ARG_WITH(screenshot,
   [AS_HELP_STRING([--with(out)-screenshot],
     [Screenshot support through libpng if available (default: with)])],
@@ -313,6 +319,25 @@ if test yes = "$with_screenshot"; then
     ])
 fi
 
+SYSTEM_ZIP=0
+SYSTEM_ZIP_CFLAGS=""
+SYSTEM_ZIP_LIBS=""
+ZIP_CFLAGS="-I../unzip"
+if test no != "$with_system_zip" && test yes = "$with_zlib" ; then
+    PKG_CHECK_MODULES([SYSTEM_ZIP],[minizip],[
+	ZIP_CFLAGS=""
+	SYSTEM_ZIP=yes
+	CFLAGS="$CFLAGS $SYSTEM_ZIP_CFLAGS -DSYSTEM_ZIP"
+	LIBS="$LIBS $SYSTEM_ZIP_LIBS"
+    ],[
+	if test check = "$with_system_zip"; then
+	    AC_MSG_WARN(Cannot find system minizip library)
+	else
+	    AC_MSG_ERROR(--with-system-zip given but cannot find system minizip library)
+	fi
+    ])
+fi
+
 if test yes = "$with_hq2x" ; then
     HQ2X=yes
     CFLAGS="$CFLAGS -DUSE_HQ2X"
@@ -440,7 +465,7 @@ if test $ac_cv_my_sar_int8 = yes && \
   CFLAGS="$CFLAGS -DRIGHTSHIFT_IS_SAR"
 fi
 
-CFLAGS="$CFLAGS -DUNZIP_SUPPORT -DSPC700_C -I. -I.. -I../unzip"
+CFLAGS="$CFLAGS -DUNZIP_SUPPORT -DSPC700_C -I. -I.. $ZIP_CFLAGS"
 
 CXXFLAGS="$CFLAGS"
 
@@ -462,6 +487,7 @@ AM_CONDITIONAL(ALSA, [test yes = "$ALSA"])
 AM_CONDITIONAL(PULSEAUDIO, [test yes = "$PULSEAUDIO"])
 AM_CONDITIONAL(HQ2X, [test yes = "$HQ2X"])
 AM_CONDITIONAL(XBRZ, [test yes = "$XBRZ"])
+AM_CONDITIONAL(SYSTEM_ZIP, [test yes = "$SYSTEM_ZIP"])
 
 AC_SUBST(NASM)
 AC_SUBST(NASM_FLAGS)
diff --git a/gtk/src/gtk_file.cpp b/gtk/src/gtk_file.cpp
index 9c0e0009..b6607f75 100644
--- a/gtk/src/gtk_file.cpp
+++ b/gtk/src/gtk_file.cpp
@@ -422,7 +422,7 @@ S9xOpenROMDialog (void)
     {
             "*.smc", "*.SMC", "*.fig", "*.FIG", "*.sfc", "*.SFC",
             "*.jma", "*.JMA", "*.zip", "*.ZIP", "*.gd3", "*.GD3",
-            "*.swc", "*.SWC", "*.gz" , "*.GZ",
+            "*.swc", "*.SWC", "*.gz" , "*.GZ", "*.bs", "*.BS",
             NULL
     };
 
diff --git a/language.h b/language.h
index c4c584f6..8304124f 100644
--- a/language.h
+++ b/language.h
@@ -208,7 +208,7 @@
 #define SAVE_INFO_LOAD					"Loaded"
 #define SAVE_INFO_OOPS					"Auto-saving 'oops' snapshot"
 #define SAVE_ERR_WRONG_FORMAT			"File not in Snes9x snapshot format"
-#define SAVE_ERR_WRONG_VERSION			"Incompatable snapshot version"
+#define SAVE_ERR_WRONG_VERSION			"Incompatible snapshot version"
 #define SAVE_ERR_ROM_NOT_FOUND			"ROM image \"%s\" for snapshot not found"
 #define SAVE_ERR_SAVE_NOT_FOUND			"Snapshot %s does not exist"
 
diff --git a/libretro/Makefile b/libretro/Makefile
index 852595bd..ea9c93ca 100644
--- a/libretro/Makefile
+++ b/libretro/Makefile
@@ -167,6 +167,8 @@ else ifneq (,$(findstring armv,$(platform)))
 		CXXFLAGS += -marm -mcpu=cortex-a8
 	else ifneq (,$(findstring cortexa9,$(platform)))
 		CXXFLAGS += -marm -mcpu=cortex-a9
+	else ifneq (,$(findstring cortexa53,$(platform)))
+		CXXFLAGS += -marm -mcpu=cortex-a53
 	endif
 	CXXFLAGS += -marm
 	ifneq (,$(findstring neon,$(platform)))
@@ -180,6 +182,14 @@ else ifneq (,$(findstring armv,$(platform)))
 	endif
 	CXXFLAGS += -DARM
 
+# Android
+else ifneq (,$(findstring android,$(platform)))
+	TARGET := $(TARGET_NAME)_libretro_android.so
+	SHARED := -shared -Wl,--no-undefined -march=armv7-a -Wl,--fix-cortex-a8
+	fpic := -fPIC
+	CXXFLAGS += -marm -march=armv7-a -mfloat-abi=softfp -mfpu=neon -DANDROID -DARM
+	HAVE_NEON = 1
+
 # Windows
 else
 	TARGET := $(TARGET_NAME)_libretro.dll
diff --git a/libretro/Makefile.common b/libretro/Makefile.common
index 3025492b..7b29c937 100644
--- a/libretro/Makefile.common
+++ b/libretro/Makefile.common
@@ -30,11 +30,14 @@ SOURCES_CXX := $(CORE_DIR)/apu/apu.cpp \
 				 $(CORE_DIR)/globals.cpp \
 				 $(CORE_DIR)/logger.cpp \
 				 $(CORE_DIR)/memmap.cpp \
+				 $(CORE_DIR)/movie.cpp \
+				 $(CORE_DIR)/msu1.cpp \
 				 $(CORE_DIR)/obc1.cpp \
 				 $(CORE_DIR)/ppu.cpp \
 				 $(CORE_DIR)/stream.cpp \
 				 $(CORE_DIR)/sa1.cpp \
 				 $(CORE_DIR)/sa1cpu.cpp \
+				 $(CORE_DIR)/screenshot.cpp \
 				 $(CORE_DIR)/sdd1.cpp \
 				 $(CORE_DIR)/sdd1emu.cpp \
 				 $(CORE_DIR)/seta.cpp \
diff --git a/libretro/libretro-win32.vcxproj b/libretro/libretro-win32.vcxproj
index adbf9f08..cfc8c204 100644
--- a/libretro/libretro-win32.vcxproj
+++ b/libretro/libretro-win32.vcxproj
@@ -222,6 +222,7 @@
     <ClInclude Include="..\messages.h" />
     <ClInclude Include="..\missing.h" />
     <ClInclude Include="..\movie.h" />
+    <ClInclude Include="..\msu1.h" />
     <ClInclude Include="..\netplay.h" />
     <ClInclude Include="..\obc1.h" />
     <ClInclude Include="..\pixform.h" />
@@ -274,6 +275,7 @@
     <ClCompile Include="..\logger.cpp" />
     <ClCompile Include="..\memmap.cpp" />
     <ClCompile Include="..\movie.cpp" />
+    <ClCompile Include="..\msu1.cpp" />
     <ClCompile Include="..\netplay.cpp" />
     <ClCompile Include="..\obc1.cpp" />
     <ClCompile Include="..\ppu.cpp" />
diff --git a/libretro/libretro-win32.vcxproj.filters b/libretro/libretro-win32.vcxproj.filters
index 998c0e74..bb0a5065 100644
--- a/libretro/libretro-win32.vcxproj.filters
+++ b/libretro/libretro-win32.vcxproj.filters
@@ -180,6 +180,9 @@
     <ClInclude Include="libretro.h">
       <Filter>libretro</Filter>
     </ClInclude>
+    <ClInclude Include="..\msu1.h">
+      <Filter>s9x-source</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\bsx.cpp">
@@ -338,5 +341,8 @@
     <ClCompile Include="libretro.cpp">
       <Filter>libretro</Filter>
     </ClCompile>
+    <ClCompile Include="..\msu1.cpp">
+      <Filter>s9x-source</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp
index 859d3f8b..08ace347 100644
--- a/libretro/libretro.cpp
+++ b/libretro/libretro.cpp
@@ -76,7 +76,7 @@ static bool rom_loaded = false;
 void retro_set_environment(retro_environment_t cb)
 {
    environ_cb = cb;
-   
+
    const struct retro_variable variables[] = {
       // These variable names and possible values constitute an ABI with ZMZ (ZSNES Libretro player).
       // Changing "Show layer 1" is fine, but don't change "layer_1"/etc or the possible values ("Yes|No").
@@ -98,7 +98,7 @@ void retro_set_environment(retro_environment_t cb)
       { "snes9x_sndchan_8", "Enable sound channel 8; Yes|No" },
       { NULL, NULL },
    };
-   
+
    environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void *)variables);
 
    const struct retro_controller_description port_1[] = {
@@ -128,9 +128,9 @@ static void update_variables(void)
 {
    char key[256];
    struct retro_variable var;
-   
+
    var.key=key;
-   
+
    int disabled_channels=0;
    strcpy(key, "snes9x_sndchan_x");
    for (int i=0;i<8;i++)
@@ -140,7 +140,7 @@ static void update_variables(void)
       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && var.value[0]=='N') disabled_channels|=1<<i;
    }
    S9xSetSoundControl(disabled_channels^0xFF);
-   
+
    int disabled_layers=0;
    strcpy(key, "snes9x_layer_x");
    for (int i=0;i<5;i++)
@@ -150,7 +150,7 @@ static void update_variables(void)
       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value && var.value[0]=='N') disabled_layers|=1<<i;
    }
    Settings.BG_Forced=disabled_layers;
-   
+
    //for some reason, Transparency seems to control both the fixed color and the windowing registers?
    var.key="snes9x_gfx_clip";
    var.value=NULL;
@@ -178,7 +178,7 @@ void retro_get_system_info(struct retro_system_info *info)
 
     info->library_name = "Snes9x";
     info->library_version = VERSION;
-    info->valid_extensions = "smc|sfc|swc|fig";
+    info->valid_extensions = "smc|sfc|swc|fig|bs";
     info->need_fullpath = false;
     info->block_extract = false;
 }
@@ -192,7 +192,7 @@ void retro_get_system_av_info(struct retro_system_av_info *info)
     info->geometry.max_width = MAX_SNES_WIDTH;
     info->geometry.max_height = MAX_SNES_HEIGHT;
     info->geometry.aspect_ratio = 4.0f / 3.0f;
-    info->timing.sample_rate = 32040.5;
+    info->timing.sample_rate = 32040;
     info->timing.fps = retro_get_region() == RETRO_REGION_NTSC ? 21477272.0 / 357366.0 : 21281370.0 / 425568.0;
 }
 
@@ -256,10 +256,10 @@ void retro_cheat_set(unsigned index, bool enabled, const char *code)
 {
    uint32 address;
    uint8 val;
-   
+
    bool8 sram;
    uint8 bytes[3];//used only by GoldFinger, ignored for now
-   
+
    if (S9xGameGenieToRaw(code, address, val)!=NULL &&
        S9xProActionReplayToRaw(code, address, val)!=NULL &&
        S9xGoldFingerToRaw(code, address, sram, val, bytes)!=NULL)
@@ -268,13 +268,13 @@ void retro_cheat_set(unsigned index, bool enabled, const char *code)
    }
    if (index>Cheat.num_cheats) return; // cheat added in weird order, ignore
    if (index==Cheat.num_cheats) Cheat.num_cheats++;
-   
+
    Cheat.c[index].address = address;
    Cheat.c[index].byte = val;
    Cheat.c[index].enabled = enabled;
-   
+
    Cheat.c[index].saved = FALSE; // it'll be saved next time cheats run anyways
-   
+
    Settings.ApplyCheats=true;
    S9xApplyCheats();
 }
@@ -374,7 +374,7 @@ bool retro_load_game(const struct retro_game_info *game)
 
    if (!rom_loaded && log_cb)
       log_cb(RETRO_LOG_ERROR, "[libretro]: Rom loading failed...\n");
-   
+
    return rom_loaded;
 }
 
@@ -387,7 +387,7 @@ bool retro_load_game_special(unsigned game_type,
    init_descriptors();
   switch (game_type) {
      case RETRO_GAME_TYPE_BSX:
-       
+
        if(num_info == 1) {
           rom_loaded = Memory.LoadROMMem((const uint8_t*)info[0].data,info[0].size);
        } else if(num_info == 2) {
@@ -399,7 +399,7 @@ bool retro_load_game_special(unsigned game_type,
           log_cb(RETRO_LOG_ERROR, "[libretro]: BSX ROM loading failed...\n");
 
        break;
-       
+
      case RETRO_GAME_TYPE_BSX_SLOTTED:
 
        if(num_info == 2)
@@ -462,8 +462,8 @@ void retro_init()
    Settings.FrameTimeNTSC = 16667;
    Settings.SixteenBitSound = TRUE;
    Settings.Stereo = TRUE;
-   Settings.SoundPlaybackRate = 32000;
-   Settings.SoundInputRate = 32000;
+   Settings.SoundPlaybackRate = 32040;
+   Settings.SoundInputRate = 32040;
    Settings.SupportHiRes = TRUE;
    Settings.Transparency = TRUE;
    Settings.AutoDisplayMessages = TRUE;
@@ -633,7 +633,7 @@ static void map_buttons()
 
 }
 
-// libretro uses relative values for analogue devices. 
+// libretro uses relative values for analogue devices.
 // S9x seems to use absolute values, but do convert these into relative values in the core. (Why?!)
 // Hack around it. :)
 static int16_t snes_mouse_state[2][2] = {{0}, {0}};
@@ -692,7 +692,7 @@ static void report_buttons()
             for (int i = JUSTIFIER_TRIGGER; i <= JUSTIFIER_LAST; i++)
                S9xReportButton(MAKE_BUTTON(2, i), input_state_cb(port, RETRO_DEVICE_LIGHTGUN, 0, i));
             break;
-            
+
          default:
             if (log_cb)
                log_cb(RETRO_LOG_ERROR, "[libretro]: Unknown device...\n");
@@ -718,14 +718,14 @@ void retro_deinit()
    Memory.Deinit();
    S9xGraphicsDeinit();
    S9xUnmapAllControls();
-   
+
    free(GFX.Screen);
 }
 
 
 unsigned retro_get_region()
-{ 
-   return Settings.PAL ? RETRO_REGION_PAL : RETRO_REGION_NTSC; 
+{
+   return Settings.PAL ? RETRO_REGION_PAL : RETRO_REGION_NTSC;
 }
 
 void* retro_get_memory_data(unsigned type)
@@ -794,7 +794,7 @@ size_t retro_serialize_size()
 }
 
 bool retro_serialize(void *data, size_t size)
-{ 
+{
    if (S9xFreezeGameMem((uint8_t*)data,size) == FALSE)
       return false;
 
@@ -802,7 +802,7 @@ bool retro_serialize(void *data, size_t size)
 }
 
 bool retro_unserialize(const void* data, size_t size)
-{ 
+{
    if (S9xUnfreezeGameMem((const uint8_t*)data,size) != SUCCESS)
       return false;
    return true;
@@ -870,8 +870,8 @@ void S9xExit() {}
 bool S9xPollPointer(unsigned int, short*, short*) { return false; }
 const char *S9xChooseMovieFilename(unsigned char) { return NULL; }
 
-bool8 S9xOpenSnapshotFile(const char* filepath, bool8 read_only, STREAM *file) 
-{ 
+bool8 S9xOpenSnapshotFile(const char* filepath, bool8 read_only, STREAM *file)
+{
    if(read_only)
    {
       if((*file = OPEN_STREAM(filepath, "rb")) != 0)
@@ -889,12 +889,12 @@ bool8 S9xOpenSnapshotFile(const char* filepath, bool8 read_only, STREAM *file)
    return (FALSE);
 }
 
-void S9xCloseSnapshotFile(STREAM file) 
+void S9xCloseSnapshotFile(STREAM file)
 {
    CLOSE_STREAM(file);
 }
 
-void S9xAutoSaveSRAM() 
+void S9xAutoSaveSRAM()
 {
    return;
 }
diff --git a/loadzip.cpp b/loadzip.cpp
index 024bc793..d3168939 100644
--- a/loadzip.cpp
+++ b/loadzip.cpp
@@ -192,7 +192,11 @@
 
 #include <assert.h>
 #include <ctype.h>
+#ifdef SYSTEM_ZIP
+#include <minizip/unzip.h>
+#else
 #include "unzip/unzip.h"
+#endif
 #include "snes9x.h"
 #include "memmap.h"
 
@@ -257,7 +261,7 @@ bool8 LoadZip (const char *zipname, uint32 *TotalFileSize, uint8 *buffer)
 	uint8	*ptr = buffer;
 	bool8	more = FALSE;
 
-	unzLocateFile(file, filename, 1);
+	unzLocateFile(file, filename, NULL);
 	unzGetCurrentFileInfo(file, &info, filename, 128, NULL, 0, NULL, 0);
 
 	if (unzOpenCurrentFile(file) != UNZ_OK)
@@ -279,7 +283,7 @@ bool8 LoadZip (const char *zipname, uint32 *TotalFileSize, uint8 *buffer)
 			return (FALSE);
 		}
 
-		if (l <= 0 || l != FileSize)
+		if (l <= 0 || l != (int) FileSize)
 		{
 			unzClose(file);
 			return (FALSE);
@@ -317,7 +321,7 @@ bool8 LoadZip (const char *zipname, uint32 *TotalFileSize, uint8 *buffer)
 
 		if (more)
 		{
-			if (unzLocateFile(file, filename, 1) != UNZ_OK ||
+			if (unzLocateFile(file, filename, NULL) != UNZ_OK ||
 				unzGetCurrentFileInfo(file, &info, filename, 128, NULL, 0, NULL, 0) != UNZ_OK ||
 				unzOpenCurrentFile(file) != UNZ_OK)
 				break;
diff --git a/memmap.cpp b/memmap.cpp
index 19df95cb..d55cfad4 100644
--- a/memmap.cpp
+++ b/memmap.cpp
@@ -193,7 +193,11 @@
 #include <assert.h>
 
 #ifdef UNZIP_SUPPORT
-#include "unzip/unzip.h"
+#  ifdef SYSTEM_ZIP
+#    include <minizip/unzip.h>
+#  else
+#    include "unzip/unzip.h"
+#  endif
 #endif
 
 #ifdef JMA_SUPPORT
@@ -201,6 +205,7 @@
 #endif
 
 #include <ctype.h>
+#include <sys/stat.h>
 
 #include "snes9x.h"
 #include "memmap.h"
@@ -952,9 +957,9 @@ static void S9xDeinterleaveGD24 (int, uint8 *);
 static bool8 allASCII (uint8 *, int);
 static bool8 is_SufamiTurbo_BIOS (const uint8 *, uint32);
 static bool8 is_SufamiTurbo_Cart (const uint8 *, uint32);
-static bool8 is_SameGame_BIOS (const uint8 *, uint32);
+static bool8 is_BSCart_BIOS (const uint8 *, uint32);
 static bool8 is_SameGame_Add_On (const uint8 *, uint32);
-static bool8 is_GNEXT_BIOS (const uint8 *, uint32);
+static bool8 is_BSCartSA1_BIOS(const uint8 *, uint32);
 static bool8 is_GNEXT_Add_On (const uint8 *, uint32);
 static uint32 caCRC32 (uint8 *, uint32, uint32 crc32 = 0xffffffff);
 static uint32 ReadUPSPointer (const uint8 *, unsigned &, unsigned);
@@ -1238,10 +1243,22 @@ static bool8 is_SufamiTurbo_Cart (const uint8 *data, uint32 size)
 		return (FALSE);
 }
 
-static bool8 is_SameGame_BIOS (const uint8 *data, uint32 size)
+static bool8 is_BSCart_BIOS(const uint8 *data, uint32 size)
 {
-	if (size == 0x100000 && strncmp((char *) (data + 0xffc0), "Same Game Tsume Game", 20) == 0)
+	if ((data[0x7FB2] == 0x5A) && (data[0x7FB5] != 0x20) && (data[0x7FDA] == 0x33))
+	{
+		Memory.LoROM = TRUE;
+		Memory.HiROM = FALSE;
+
 		return (TRUE);
+	}
+	else if ((data[0xFFB2] == 0x5A) && (data[0xFFB5] != 0x20) && (data[0xFFDA] == 0x33))
+	{
+		Memory.LoROM = FALSE;
+		Memory.HiROM = TRUE;
+
+		return (TRUE);
+	}
 	else
 		return (FALSE);
 }
@@ -1254,9 +1271,14 @@ static bool8 is_SameGame_Add_On (const uint8 *data, uint32 size)
 		return (FALSE);
 }
 
-static bool8 is_GNEXT_BIOS (const uint8 *data, uint32 size)
+static bool8 is_BSCartSA1_BIOS (const uint8 *data, uint32 size)
 {
-	if (size == 0x180000 && strncmp((char *) (data + 0x7fc0), "SFC SDGUNDAMGNEXT", 17) == 0)
+	//Same basic check as BSCart
+	if (!is_BSCart_BIOS(data, size))
+		return (FALSE);
+
+	//Checks if the game is Itoi's Bass Fishing No. 1 (ZBPJ) or SD Gundam G-NEXT (ZX3J)
+	if (strncmp((char *)(data + 0x7fb2), "ZBPJ", 4) == 0 || strncmp((char *)(data + 0x7fb2), "ZX3J", 4) == 0)
 		return (TRUE);
 	else
 		return (FALSE);
@@ -1861,11 +1883,11 @@ bool8 CMemory::LoadMultiCartInt ()
         if (is_SufamiTurbo_Cart(ROM + Multi.cartOffsetA, Multi.cartSizeA))
 			Multi.cartType = 4;
 		else
-		if (is_SameGame_BIOS(ROM + Multi.cartOffsetA, Multi.cartSizeA))
-			Multi.cartType = 3;
-		else
-		if (is_GNEXT_BIOS(ROM + Multi.cartOffsetA, Multi.cartSizeA))
+		if (is_BSCartSA1_BIOS(ROM + Multi.cartOffsetA, Multi.cartSizeA))
 			Multi.cartType = 5;
+		else
+		if (is_BSCart_BIOS(ROM + Multi.cartOffsetA, Multi.cartSizeA))
+			Multi.cartType = 3;		
 	}
 	else
 	if (Multi.cartSizeB)
@@ -1883,7 +1905,7 @@ bool8 CMemory::LoadMultiCartInt ()
             memmove(ROM + Multi.cartOffsetA, ROM, Multi.cartSizeA + Multi.cartSizeB);
         else if(Multi.cartOffsetB) // clear cart A so the bios can detect that it's not present
             memset(ROM, 0, Multi.cartOffsetB);
-        
+
         FILE	*fp;
 	    size_t	size;
 	    char	path[PATH_MAX + 1];
@@ -1913,11 +1935,8 @@ bool8 CMemory::LoadMultiCartInt ()
 			break;
 
 		case 3:
-			r = LoadSameGame();
-			break;
-
 		case 5:
-			r = LoadGNEXT();
+			r = LoadBSCart();
 			break;
 
 		default:
@@ -1981,26 +2000,31 @@ bool8 CMemory::LoadSufamiTurbo ()
 	return (TRUE);
 }
 
-bool8 CMemory::LoadSameGame ()
+bool8 CMemory::LoadBSCart ()
 {
 	Multi.sramA = SRAM;
 	Multi.sramB = NULL;
 
-	Multi.sramSizeA = ROM[0xffd8];
+	if (LoROM)
+		Multi.sramSizeA = ROM[0x7fd8];
+	else
+		Multi.sramSizeA = ROM[0xffd8];
+
 	Multi.sramMaskA = Multi.sramSizeA ? ((1 << (Multi.sramSizeA + 3)) * 128 - 1) : 0;
 	Multi.sramSizeB = 0;
 	Multi.sramMaskB = 0;
 
-	if (Multi.cartSizeB)
-	{
-		if (!is_SameGame_Add_On(ROM + Multi.cartOffsetB, Multi.cartSizeB))
-			Multi.cartSizeB = 0;
-	}
-
-	LoROM = FALSE;
-	HiROM = TRUE;
 	CalculatedSize = Multi.cartSizeA;
 
+	if (Multi.cartSizeB == 0 && Multi.cartSizeA <= (MAX_ROM_SIZE - 0x100000 - Multi.cartOffsetA))
+	{
+		//Initialize 1MB Empty Memory Pack only if cart B is cleared
+		//It does not make a Memory Pack if game is loaded like a normal ROM
+		Multi.cartOffsetB = Multi.cartOffsetA + CalculatedSize;
+		Multi.cartSizeB = 0x100000;
+		memset(Memory.ROM + Multi.cartOffsetB, 0xFF, 0x100000);
+	}
+
 	return (TRUE);
 }
 
@@ -2209,6 +2233,32 @@ bool8 CMemory::SaveSRAM (const char *filename)
 	return (FALSE);
 }
 
+bool8 CMemory::SaveMPAK (const char *filename)
+{
+	if (Settings.BS || (Multi.cartSizeB && (Multi.cartType == 3)))
+	{
+		FILE	*file;
+		int		size;
+		char	mempakName[PATH_MAX + 1];
+
+		strcpy(mempakName, filename);
+		size = 0x100000;
+		if (size)
+		{
+			file = fopen(mempakName, "wb");
+			if (file)
+			{
+				size_t	ignore;
+				ignore = fwrite((char *)Memory.ROM + Multi.cartOffsetB, size, 1, file);
+				fclose(file);
+
+				return (TRUE);
+			}
+		}
+	}
+	return (FALSE);
+}
+
 // initialization
 
 static uint32 caCRC32 (uint8 *array, uint32 size, uint32 crc32)
@@ -2360,6 +2410,7 @@ void CMemory::InitROM (void)
 	Settings.SETA = 0;
 	Settings.SRTC = FALSE;
 	Settings.BS = FALSE;
+	Settings.MSU1 = FALSE;
 
 	SuperFX.nRomBanks = CalculatedSize >> 15;
 
@@ -2534,6 +2585,9 @@ void CMemory::InitROM (void)
 			break;
 	}
 
+	// MSU1
+	Settings.MSU1 = S9xMSU1ROMExists();
+
 	//// Map memory and calculate checksum
 
 	Map_Initialize();
@@ -2551,7 +2605,7 @@ void CMemory::InitROM (void)
 			Map_ExtendedHiROMMap();
 		else
 		if (Multi.cartType == 3)
-			Map_SameGameHiROMMap();
+			Map_BSCartHiROMMap();
 		else
 			Map_HiROMMap();
     }
@@ -2569,7 +2623,7 @@ void CMemory::InitROM (void)
 		if (Settings.SA1)
 		{
 			if (Multi.cartType == 5)
-				Map_GNEXTSA1LoROMMap();
+				Map_BSSA1LoROMMap();
 			else
 				Map_SA1LoROMMap();
 		}
@@ -2583,6 +2637,13 @@ void CMemory::InitROM (void)
 		if (strncmp(ROMName, "WANDERERS FROM YS", 17) == 0)
 			Map_NoMAD1LoROMMap();
 		else
+		if (Multi.cartType == 3)
+			if (strncmp(ROMName, "SOUND NOVEL-TCOOL", 17) == 0 ||
+				strncmp(ROMName, "DERBY STALLION 96", 17) == 0)
+				Map_BSCartLoROMMap(1);
+			else
+				Map_BSCartLoROMMap(0);
+		else
 		if (strncmp(ROMName, "SOUND NOVEL-TCOOL", 17) == 0 ||
 			strncmp(ROMName, "DERBY STALLION 96", 17) == 0)
 			Map_ROM24MBSLoROMMap();
@@ -3254,9 +3315,9 @@ void CMemory::Map_SA1LoROMMap (void)
 	BWRAM = SRAM;
 }
 
-void CMemory::Map_GNEXTSA1LoROMMap (void)
+void CMemory::Map_BSSA1LoROMMap(void)
 {
-	printf("Map_GNEXTSA1LoROMMap\n");
+	printf("Map_BSSA1LoROMMap\n");
 	map_System();
 
 	map_lorom_offset(0x00, 0x3f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
@@ -3272,9 +3333,6 @@ void CMemory::Map_GNEXTSA1LoROMMap (void)
 	for (int c = 0x40; c < 0x80; c++)
 		map_space(c, c, 0x0000, 0xffff, SRAM + (c & 1) * 0x10000);
 
-	// FIXME: untested!
-	map_hirom_offset(0x70, 0x7f, 0x0000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
-
 	map_WRAM();
 
 	map_WriteProtectROM();
@@ -3334,26 +3392,6 @@ void CMemory::Map_ExtendedHiROMMap (void)
 	map_WriteProtectROM();
 }
 
-void CMemory::Map_SameGameHiROMMap (void)
-{
-	printf("Map_SameGameHiROMMap\n");
-	map_System();
-
-	map_hirom_offset(0x00, 0x1f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
-	map_hirom_offset(0x20, 0x3f, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
-	map_hirom_offset(0x40, 0x5f, 0x0000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
-	map_hirom_offset(0x60, 0x7f, 0x0000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
-	map_hirom_offset(0x80, 0x9f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
-	map_hirom_offset(0xa0, 0xbf, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
-	map_hirom_offset(0xc0, 0xdf, 0x0000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
-	map_hirom_offset(0xe0, 0xff, 0x0000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
-
-	map_HiROMSRAM();
-	map_WRAM();
-
-	map_WriteProtectROM();
-}
-
 void CMemory::Map_SPC7110HiROMMap (void)
 {
 	printf("Map_SPC7110HiROMMap\n");
@@ -3372,6 +3410,71 @@ void CMemory::Map_SPC7110HiROMMap (void)
 	map_WriteProtectROM();
 }
 
+void CMemory::Map_BSCartLoROMMap(uint8 mapping)
+{
+	printf("Map_BSCartLoROMMap\n");
+
+	BSX.MMC[0x02] = 0x00;
+	BSX.MMC[0x0C] = 0x80;
+
+	map_System();
+
+	if (mapping)
+	{
+		map_lorom_offset(0x00, 0x1f, 0x8000, 0xffff, 0x100000, 0);
+		map_lorom_offset(0x20, 0x3f, 0x8000, 0xffff, 0x100000, 0x100000);
+		map_lorom_offset(0x80, 0x9f, 0x8000, 0xffff, 0x100000, 0x200000);
+		map_lorom_offset(0xa0, 0xbf, 0x8000, 0xffff, 0x100000, 0x100000);
+	}
+	else
+	{
+		map_lorom(0x00, 0x3f, 0x8000, 0xffff, CalculatedSize);
+		map_lorom(0x40, 0x7f, 0x0000, 0x7fff, CalculatedSize);
+		map_lorom(0x80, 0xbf, 0x8000, 0xffff, CalculatedSize);
+		map_lorom(0xc0, 0xff, 0x0000, 0x7fff, CalculatedSize);
+	}
+
+	map_LoROMSRAM();
+	map_index(0xc0, 0xef, 0x0000, 0xffff, MAP_BSX, MAP_TYPE_RAM);
+	map_WRAM();
+
+	map_WriteProtectROM();
+}
+
+void CMemory::Map_BSCartHiROMMap(void)
+{
+	printf("Map_BSCartHiROMMap\n");
+
+	BSX.MMC[0x02] = 0x80;
+	BSX.MMC[0x0C] = 0x80;
+
+	map_System();
+	map_hirom_offset(0x00, 0x1f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
+	map_hirom_offset(0x20, 0x3f, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
+	map_hirom_offset(0x40, 0x5f, 0x0000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
+	map_hirom_offset(0x60, 0x7f, 0x0000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
+	map_hirom_offset(0x80, 0x9f, 0x8000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
+	map_hirom_offset(0xa0, 0xbf, 0x8000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
+	map_hirom_offset(0xc0, 0xdf, 0x0000, 0xffff, Multi.cartSizeA, Multi.cartOffsetA);
+
+	if ((ROM[Multi.cartOffsetB + 0xFF00] == 0x4D)
+		&& (ROM[Multi.cartOffsetB + 0xFF02] == 0x50)
+		&& ((ROM[Multi.cartOffsetB + 0xFF06] & 0xF0) == 0x70))
+	{
+		//Type 7 Memory Pack detection - if detected, emulate it as Mask ROM
+		map_hirom_offset(0xe0, 0xff, 0x0000, 0xffff, Multi.cartSizeB, Multi.cartOffsetB);
+	}
+	else
+	{
+		map_index(0xe0, 0xff, 0x0000, 0xffff, MAP_BSX, MAP_TYPE_RAM);
+	}
+
+	map_HiROMSRAM();
+	map_WRAM();
+
+	map_WriteProtectROM();
+}
+
 // checksum
 
 uint16 CMemory::checksum_calc_sum (uint8 *data, uint32 length)
@@ -3486,7 +3589,7 @@ const char * CMemory::KartContents (void)
 	static char			str[64];
 	static const char	*contents[3] = { "ROM", "ROM+RAM", "ROM+RAM+BAT" };
 
-	char	chip[16];
+	char	chip[20];
 
 	if (ROMType == 0 && !Settings.BS)
 		return ("ROM");
@@ -3532,6 +3635,9 @@ const char * CMemory::KartContents (void)
 	else
 		strcpy(chip, "");
 
+	if (Settings.MSU1)
+		sprintf(chip + strlen(chip), "+MSU-1");
+
 	sprintf(str, "%s%s", contents[(ROMType & 0xf) % 3], chip);
 
 	return (str);
@@ -4128,8 +4234,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 	{
 		printf("Using BPS patch %s", fname);
 
-		ret = ReadBPSPatch(new fStream(patch_file), 0, rom_size);
-        CLOSE_FSTREAM(patch_file);
+        Stream *s = new fStream(patch_file);
+		ret = ReadBPSPatch(s, 0, rom_size);
+        s->closeStream();
 
 		if (ret)
 		{
@@ -4151,8 +4258,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 			{
 				printf(" in %s", rom_filename);
 
-				ret = ReadBPSPatch(new unzStream(file), offset, rom_size);
-				unzCloseCurrentFile(file);
+                Stream *s = new unzStream(file);
+				ret = ReadBPSPatch(s, offset, rom_size);
+                s->closeStream();
 
 				if (ret)
 					printf("!\n");
@@ -4169,8 +4277,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 	{
 		printf("Using BPS patch %s", n);
 
-		ret = ReadBPSPatch(new fStream(patch_file), 0, rom_size);
-        CLOSE_FSTREAM(patch_file);
+        Stream *s = new fStream(patch_file);
+		ret = ReadBPSPatch(s, 0, rom_size);
+        s->closeStream();
 
 		if (ret)
 		{
@@ -4189,8 +4298,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 	{
 		printf("Using UPS patch %s", fname);
 
-		ret = ReadUPSPatch(new fStream(patch_file), 0, rom_size);
-        CLOSE_FSTREAM(patch_file);
+        Stream *s = new fStream(patch_file);
+		ret = ReadUPSPatch(s, 0, rom_size);
+        s->closeStream();
 
 		if (ret)
 		{
@@ -4212,8 +4322,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 			{
 				printf(" in %s", rom_filename);
 
-				ret = ReadUPSPatch(new unzStream(file), offset, rom_size);
-				unzCloseCurrentFile(file);
+                Stream *s = new unzStream(file);
+				ret = ReadUPSPatch(s, offset, rom_size);
+                s->closeStream();
 
 				if (ret)
 					printf("!\n");
@@ -4230,8 +4341,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 	{
 		printf("Using UPS patch %s", n);
 
-		ret = ReadUPSPatch(new fStream(patch_file), 0, rom_size);
-        CLOSE_FSTREAM(patch_file);
+        Stream *s = new fStream(patch_file);
+		ret = ReadUPSPatch(s, 0, rom_size);
+        s->closeStream();
 
 		if (ret)
 		{
@@ -4250,8 +4362,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 	{
 		printf("Using IPS patch %s", fname);
 
-		ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
-        CLOSE_FSTREAM(patch_file);
+        Stream *s = new fStream(patch_file);
+		ret = ReadIPSPatch(s, offset, rom_size);
+        s->closeStream();
 
 		if (ret)
 		{
@@ -4277,8 +4390,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 
 			printf("Using IPS patch %s", fname);
 
-			ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
-            CLOSE_FSTREAM(patch_file);
+            Stream *s = new fStream(patch_file);
+			ret = ReadIPSPatch(s, offset, rom_size);
+            s->closeStream();
 
 			if (ret)
 			{
@@ -4313,8 +4427,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 
 			printf("Using IPS patch %s", fname);
 
-			ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
-            CLOSE_FSTREAM(patch_file);
+            Stream *s = new fStream(patch_file);
+			ret = ReadIPSPatch(s, offset, rom_size);
+            s->closeStream();
 
 			if (ret)
 			{
@@ -4347,8 +4462,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 
 			printf("Using IPS patch %s", fname);
 
-			ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
-            CLOSE_FSTREAM(patch_file);
+            Stream *s = new fStream(patch_file);
+			ret = ReadIPSPatch(s, offset, rom_size);
+            s->closeStream();
 
 			if (ret)
 			{
@@ -4377,8 +4493,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 			{
 				printf(" in %s", rom_filename);
 
-				ret = ReadIPSPatch(new unzStream(file), offset, rom_size);
-				unzCloseCurrentFile(file);
+                Stream *s = new unzStream(file);
+				ret = ReadIPSPatch(s, offset, rom_size);
+                s->closeStream();
 
 				if (ret)
 				{
@@ -4404,8 +4521,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 
 					printf(" in %s", rom_filename);
 
-					ret = ReadIPSPatch(new unzStream(file), offset, rom_size);
-					unzCloseCurrentFile(file);
+                    Stream *s = new unzStream(file);
+					ret = ReadIPSPatch(s, offset, rom_size);
+                    s->closeStream();
 
 					if (ret)
 					{
@@ -4438,8 +4556,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 
 					printf(" in %s", rom_filename);
 
-					ret = ReadIPSPatch(new unzStream(file), offset, rom_size);
-					unzCloseCurrentFile(file);
+                    Stream *s = new unzStream(file);
+					ret = ReadIPSPatch(s, offset, rom_size);
+                    s->closeStream();
 
 					if (ret)
 					{
@@ -4470,8 +4589,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 
 					printf(" in %s", rom_filename);
 
-					ret = ReadIPSPatch(new unzStream(file), offset, rom_size);
-					unzCloseCurrentFile(file);
+                    Stream *s = new unzStream(file);
+					ret = ReadIPSPatch(s, offset, rom_size);
+                    s->closeStream();
 
 					if (ret)
 					{
@@ -4503,8 +4623,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 	{
 		printf("Using IPS patch %s", n);
 
-		ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
-        CLOSE_FSTREAM(patch_file);
+        Stream *s = new fStream(patch_file);
+		ret = ReadIPSPatch(s, offset, rom_size);
+        s->closeStream();
 
 		if (ret)
 		{
@@ -4530,8 +4651,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 
 			printf("Using IPS patch %s", n);
 
-			ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
-            CLOSE_FSTREAM(patch_file);
+            Stream *s = new fStream(patch_file);
+			ret = ReadIPSPatch(s, offset, rom_size);
+            s->closeStream();
 
 			if (ret)
 			{
@@ -4566,8 +4688,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 
 			printf("Using IPS patch %s", n);
 
-			ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
-            CLOSE_FSTREAM(patch_file);
+            Stream *s = new fStream(patch_file);
+			ret = ReadIPSPatch(s, offset, rom_size);
+            s->closeStream();
 
 			if (ret)
 			{
@@ -4600,8 +4723,9 @@ void CMemory::CheckForAnyPatch (const char *rom_filename, bool8 header, int32 &r
 
 			printf("Using IPS patch %s", n);
 
-			ret = ReadIPSPatch(new fStream(patch_file), offset, rom_size);
-            CLOSE_FSTREAM(patch_file);
+            Stream *s = new fStream(patch_file);
+			ret = ReadIPSPatch(s, offset, rom_size);
+            s->closeStream();
 
 			if (ret)
 			{
diff --git a/memmap.h b/memmap.h
index 6db01a7f..53826a98 100644
--- a/memmap.h
+++ b/memmap.h
@@ -293,13 +293,14 @@ struct CMemory
 	bool8	LoadMultiCart (const char *, const char *);
     bool8	LoadMultiCartInt ();
 	bool8	LoadSufamiTurbo ();
-	bool8	LoadSameGame ();
+	bool8	LoadBSCart ();
 	bool8	LoadGNEXT ();
 	bool8	LoadSRAM (const char *);
 	bool8	SaveSRAM (const char *);
 	void	ClearSRAM (bool8 onlyNonSavedSRAM = 0);
 	bool8	LoadSRTC (void);
 	bool8	SaveSRTC (void);
+	bool8	SaveMPAK (const char *);
 
 	char *	Safe (const char *);
 	char *	SafeANK (const char *);
@@ -335,11 +336,12 @@ struct CMemory
 	void	Map_SetaDSPLoROMMap (void);
 	void	Map_SDD1LoROMMap (void);
 	void	Map_SA1LoROMMap (void);
-	void	Map_GNEXTSA1LoROMMap (void);
+	void	Map_BSSA1LoROMMap (void);
 	void	Map_HiROMMap (void);
 	void	Map_ExtendedHiROMMap (void);
-	void	Map_SameGameHiROMMap (void);
 	void	Map_SPC7110HiROMMap (void);
+	void	Map_BSCartLoROMMap(uint8);
+	void	Map_BSCartHiROMMap(void);
 
 	uint16	checksum_calc_sum (uint8 *, uint32);
 	uint16	checksum_mirror_sum (uint8 *, uint32 &, uint32 mask = 0x800000);
diff --git a/movie.cpp b/movie.cpp
index af2d8b3f..87426b1f 100644
--- a/movie.cpp
+++ b/movie.cpp
@@ -807,7 +807,9 @@ int S9xMovieOpen (const char *filename, bool8 read_only)
 	restore_movie_settings();
 
 	lseek(fn, Movie.SaveStateOffset, SEEK_SET);
-	stream = REOPEN_STREAM(fn, "rb");
+
+    // reopen stream to access as gzipped data
+    stream = REOPEN_STREAM(fn, "rb");
 	if (!stream)
 		return (FILE_NOT_FOUND);
 
@@ -820,7 +822,11 @@ int S9xMovieOpen (const char *filename, bool8 read_only)
 	else
 		result = S9xUnfreezeFromStream(stream);
 
-	CLOSE_STREAM(stream);
+    // do not close stream but close FILE *
+    // (msvcrt will try to close all open FILE *handles on exit - if we do CLOSE_STREAM here
+    //  the underlying file will be closed by zlib, causing problems when msvcrt tries to do it)
+    delete stream;
+    fclose(fd);
 
 	if (result != SUCCESS)
 		return (result);
diff --git a/msu1.cpp b/msu1.cpp
new file mode 100644
index 00000000..4ad05419
--- /dev/null
+++ b/msu1.cpp
@@ -0,0 +1,490 @@
+/***********************************************************************************
+  Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
+
+  (c) Copyright 1996 - 2002  Gary Henderson (gary.henderson@ntlworld.com),
+                             Jerremy Koot (jkoot@snes9x.com)
+
+  (c) Copyright 2002 - 2004  Matthew Kendora
+
+  (c) Copyright 2002 - 2005  Peter Bortas (peter@bortas.org)
+
+  (c) Copyright 2004 - 2005  Joel Yliluoma (http://iki.fi/bisqwit/)
+
+  (c) Copyright 2001 - 2006  John Weidman (jweidman@slip.net)
+
+  (c) Copyright 2002 - 2006  funkyass (funkyass@spam.shaw.ca),
+                             Kris Bleakley (codeviolation@hotmail.com)
+
+  (c) Copyright 2002 - 2010  Brad Jorsch (anomie@users.sourceforge.net),
+                             Nach (n-a-c-h@users.sourceforge.net),
+
+  (c) Copyright 2002 - 2011  zones (kasumitokoduck@yahoo.com)
+
+  (c) Copyright 2006 - 2007  nitsuja
+
+  (c) Copyright 2009 - 2016  BearOso,
+                             OV2
+
+  (c) Copyright 2011 - 2016  Hans-Kristian Arntzen,
+                             Daniel De Matteis
+                             (Under no circumstances will commercial rights be given)
+
+
+  BS-X C emulator code
+  (c) Copyright 2005 - 2006  Dreamer Nom,
+                             zones
+
+  C4 x86 assembler and some C emulation code
+  (c) Copyright 2000 - 2003  _Demo_ (_demo_@zsnes.com),
+                             Nach,
+                             zsKnight (zsknight@zsnes.com)
+
+  C4 C++ code
+  (c) Copyright 2003 - 2006  Brad Jorsch,
+                             Nach
+
+  DSP-1 emulator code
+  (c) Copyright 1998 - 2006  _Demo_,
+                             Andreas Naive (andreasnaive@gmail.com),
+                             Gary Henderson,
+                             Ivar (ivar@snes9x.com),
+                             John Weidman,
+                             Kris Bleakley,
+                             Matthew Kendora,
+                             Nach,
+                             neviksti (neviksti@hotmail.com)
+
+  DSP-2 emulator code
+  (c) Copyright 2003         John Weidman,
+                             Kris Bleakley,
+                             Lord Nightmare (lord_nightmare@users.sourceforge.net),
+                             Matthew Kendora,
+                             neviksti
+
+  DSP-3 emulator code
+  (c) Copyright 2003 - 2006  John Weidman,
+                             Kris Bleakley,
+                             Lancer,
+                             z80 gaiden
+
+  DSP-4 emulator code
+  (c) Copyright 2004 - 2006  Dreamer Nom,
+                             John Weidman,
+                             Kris Bleakley,
+                             Nach,
+                             z80 gaiden
+
+  OBC1 emulator code
+  (c) Copyright 2001 - 2004  zsKnight,
+                             pagefault (pagefault@zsnes.com),
+                             Kris Bleakley
+                             Ported from x86 assembler to C by sanmaiwashi
+
+  SPC7110 and RTC C++ emulator code used in 1.39-1.51
+  (c) Copyright 2002         Matthew Kendora with research by
+                             zsKnight,
+                             John Weidman,
+                             Dark Force
+
+  SPC7110 and RTC C++ emulator code used in 1.52+
+  (c) Copyright 2009         byuu,
+                             neviksti
+
+  S-DD1 C emulator code
+  (c) Copyright 2003         Brad Jorsch with research by
+                             Andreas Naive,
+                             John Weidman
+
+  S-RTC C emulator code
+  (c) Copyright 2001 - 2006  byuu,
+                             John Weidman
+
+  ST010 C++ emulator code
+  (c) Copyright 2003         Feather,
+                             John Weidman,
+                             Kris Bleakley,
+                             Matthew Kendora
+
+  Super FX x86 assembler emulator code
+  (c) Copyright 1998 - 2003  _Demo_,
+                             pagefault,
+                             zsKnight
+
+  Super FX C emulator code
+  (c) Copyright 1997 - 1999  Ivar,
+                             Gary Henderson,
+                             John Weidman
+
+  Sound emulator code used in 1.5-1.51
+  (c) Copyright 1998 - 2003  Brad Martin
+  (c) Copyright 1998 - 2006  Charles Bilyue'
+
+  Sound emulator code used in 1.52+
+  (c) Copyright 2004 - 2007  Shay Green (gblargg@gmail.com)
+
+  S-SMP emulator code used in 1.54+
+  (c) Copyright 2016         byuu
+
+  SH assembler code partly based on x86 assembler code
+  (c) Copyright 2002 - 2004  Marcus Comstedt (marcus@mc.pp.se)
+
+  2xSaI filter
+  (c) Copyright 1999 - 2001  Derek Liauw Kie Fa
+
+  HQ2x, HQ3x, HQ4x filters
+  (c) Copyright 2003         Maxim Stepin (maxim@hiend3d.com)
+
+  NTSC filter
+  (c) Copyright 2006 - 2007  Shay Green
+
+  GTK+ GUI code
+  (c) Copyright 2004 - 2016  BearOso
+
+  Win32 GUI code
+  (c) Copyright 2003 - 2006  blip,
+                             funkyass,
+                             Matthew Kendora,
+                             Nach,
+                             nitsuja
+  (c) Copyright 2009 - 2016  OV2
+
+  Mac OS GUI code
+  (c) Copyright 1998 - 2001  John Stiles
+  (c) Copyright 2001 - 2011  zones
+
+  Libretro port
+  (c) Copyright 2011 - 2016  Hans-Kristian Arntzen,
+                             Daniel De Matteis
+                             (Under no circumstances will commercial rights be given)
+
+  MSU-1 code
+  (c) Copyright 2016         qwertymodo
+
+
+  Specific ports contains the works of other authors. See headers in
+  individual files.
+
+
+  Snes9x homepage: http://www.snes9x.com/
+
+  Permission to use, copy, modify and/or distribute Snes9x in both binary
+  and source form, for non-commercial purposes, is hereby granted without
+  fee, providing that this license information and copyright notice appear
+  with all copies and any derived work.
+
+  This software is provided 'as-is', without any express or implied
+  warranty. In no event shall the authors be held liable for any damages
+  arising from the use of this software or it's derivatives.
+
+  Snes9x is freeware for PERSONAL USE only. Commercial users should
+  seek permission of the copyright holders first. Commercial use includes,
+  but is not limited to, charging money for Snes9x or software derived from
+  Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
+  using Snes9x as a promotion for your commercial product.
+
+  The copyright holders request that bug fixes and improvements to the code
+  should be forwarded to them so everyone can benefit from the modifications
+  in future versions.
+
+  Super NES and Super Nintendo Entertainment System are trademarks of
+  Nintendo Co., Limited and its subsidiary companies.
+ ***********************************************************************************/
+
+#include "snes9x.h"
+#include "display.h"
+#include "msu1.h"
+#include "apu/bapu/dsp/blargg_endian.h"
+#include <fstream>
+#include <sys/stat.h>
+
+std::ifstream dataFile, audioFile;
+uint32 audioLoopPos;
+uint32 partial_samples;
+
+// Sample buffer
+int16 *bufPos, *bufBegin, *bufEnd;
+
+bool AudioOpen()
+{
+	MSU1.MSU1_STATUS |= AudioError;
+
+	if (audioFile.is_open())
+		audioFile.close();
+
+	char ext[_MAX_EXT];
+	snprintf(ext, _MAX_EXT, "-%d.pcm", MSU1.MSU1_CURRENT_TRACK);
+
+	audioFile.clear();
+	audioFile.open(S9xGetFilename(ext, ROMFILENAME_DIR), std::ios::in | std::ios::binary);
+	if (audioFile.good())
+	{
+		if (audioFile.get() != 'M')
+			return false;
+		if (audioFile.get() != 'S')
+			return false;
+		if (audioFile.get() != 'U')
+			return false;
+		if (audioFile.get() != '1')
+			return false;
+
+		audioFile.read((char *)&audioLoopPos, 4);
+		audioLoopPos = GET_LE32(&audioLoopPos);
+		audioLoopPos <<= 2;
+		audioLoopPos += 8;
+
+		MSU1.MSU1_STATUS &= ~AudioError;
+		return true;
+	}
+
+	return false;
+}
+
+bool DataOpen()
+{
+	if (dataFile.is_open())
+		dataFile.close();
+
+	dataFile.clear();
+	dataFile.open(S9xGetFilename(".msu", ROMFILENAME_DIR), std::ios::in | std::ios::binary);
+	return dataFile.is_open();
+}
+
+void S9xResetMSU(void)
+{
+	MSU1.MSU1_STATUS		= 0;
+	MSU1.MSU1_DATA_SEEK		= 0;
+	MSU1.MSU1_DATA_POS		= 0;
+	MSU1.MSU1_TRACK_SEEK	= 0;
+	MSU1.MSU1_CURRENT_TRACK = 0;
+	MSU1.MSU1_RESUME_TRACK	= 0;
+	MSU1.MSU1_VOLUME		= 0;
+	MSU1.MSU1_CONTROL		= 0;
+	MSU1.MSU1_AUDIO_POS		= 0;
+	MSU1.MSU1_RESUME_POS	= 0;
+
+
+	bufPos				= 0;
+	bufBegin			= 0;
+	bufEnd				= 0;
+
+	partial_samples = 0;
+
+	if (dataFile.is_open())
+		dataFile.close();
+
+	if (audioFile.is_open())
+		audioFile.close();
+
+	Settings.MSU1 = S9xMSU1ROMExists();
+}
+
+void S9xMSU1Init(void)
+{
+	S9xResetMSU();
+	DataOpen();
+}
+
+bool S9xMSU1ROMExists(void)
+{
+	struct stat buf;
+	return (stat(S9xGetFilename(".msu", ROMFILENAME_DIR), &buf) == 0);
+}
+
+void S9xMSU1Generate(int sample_count)
+{
+	partial_samples += 44100 * sample_count;
+
+	while (((uintptr_t)bufPos < (uintptr_t)bufEnd) && (MSU1.MSU1_STATUS & AudioPlaying) && partial_samples > 32040)
+	{
+		if (audioFile.is_open())
+		{
+			int16 sample;
+			if (audioFile.read((char *)&sample, 2).good())
+			{
+				sample = (int16)((double)(int16)GET_LE16(&sample) * (double)MSU1.MSU1_VOLUME / 255.0);
+
+				*(bufPos++) = sample;
+				MSU1.MSU1_AUDIO_POS += 2;
+				partial_samples -= 32040;
+			}
+			else
+			if (audioFile.eof())
+			{
+				sample = (int16)((double)(int16)GET_LE16(&sample) * (double)MSU1.MSU1_VOLUME / 255.0);
+
+				*(bufPos++) = sample;
+				MSU1.MSU1_AUDIO_POS += 2;
+				partial_samples -= 32040;
+
+				if (MSU1.MSU1_STATUS & AudioRepeating)
+				{
+					audioFile.clear();
+					MSU1.MSU1_AUDIO_POS = audioLoopPos;
+					audioFile.seekg(MSU1.MSU1_AUDIO_POS);
+				}
+				else
+				{
+					MSU1.MSU1_STATUS &= ~(AudioPlaying | AudioRepeating);
+					audioFile.clear();
+					audioFile.seekg(8);
+					return;
+				}
+			}
+			else
+			{
+				MSU1.MSU1_STATUS &= ~(AudioPlaying | AudioRepeating);
+				return;
+			}
+		}
+		else
+		{
+			MSU1.MSU1_STATUS &= ~(AudioPlaying | AudioRepeating);
+			return;
+		}
+	}
+}
+
+
+uint8 S9xMSU1ReadPort(int port)
+{
+	switch (port)
+	{
+	case 0:
+		return MSU1.MSU1_STATUS;
+	case 1:
+		if (MSU1.MSU1_STATUS & DataBusy)
+			return 0;
+		if (dataFile.fail() || dataFile.bad() || dataFile.eof())
+			return 0;
+		MSU1.MSU1_DATA_POS++;
+		return dataFile.get();
+	case 2:
+		return 'S';
+	case 3:
+		return '-';
+	case 4:
+		return 'M';
+	case 5:
+		return 'S';
+	case 6:
+		return 'U';
+	case 7:
+		return '1';
+	}
+
+	return 0;
+}
+
+
+void S9xMSU1WritePort(int port, uint8 byte)
+{
+	switch (port)
+	{
+	case 0:
+		MSU1.MSU1_DATA_SEEK &= 0xFFFFFF00;
+		MSU1.MSU1_DATA_SEEK |= byte << 0;
+		break;
+	case 1:
+		MSU1.MSU1_DATA_SEEK &= 0xFFFF00FF;
+		MSU1.MSU1_DATA_SEEK |= byte << 8;
+		break;
+	case 2:
+		MSU1.MSU1_DATA_SEEK &= 0xFF00FFFF;
+		MSU1.MSU1_DATA_SEEK |= byte << 16;
+		break;
+	case 3:
+		MSU1.MSU1_DATA_SEEK &= 0x00FFFFFF;
+		MSU1.MSU1_DATA_SEEK |= byte << 24;
+		MSU1.MSU1_DATA_POS = MSU1.MSU1_DATA_SEEK;
+		if(dataFile.good())
+			dataFile.seekg(MSU1.MSU1_DATA_POS);
+		break;
+	case 4:
+		MSU1.MSU1_TRACK_SEEK &= 0xFF00;
+		MSU1.MSU1_TRACK_SEEK |= byte;
+		break;
+	case 5:
+		MSU1.MSU1_TRACK_SEEK &= 0x00FF;
+		MSU1.MSU1_TRACK_SEEK |= (byte << 8);
+		MSU1.MSU1_CURRENT_TRACK = MSU1.MSU1_TRACK_SEEK;
+
+		MSU1.MSU1_STATUS &= ~AudioPlaying;
+		MSU1.MSU1_STATUS &= ~AudioRepeating;
+
+		if (AudioOpen())
+		{
+			if (MSU1.MSU1_CURRENT_TRACK == MSU1.MSU1_RESUME_TRACK)
+			{
+				MSU1.MSU1_AUDIO_POS = MSU1.MSU1_RESUME_POS;
+				MSU1.MSU1_RESUME_POS = 0;
+				MSU1.MSU1_RESUME_TRACK = ~0;
+			}
+			else
+			{
+				MSU1.MSU1_AUDIO_POS = 8;
+			}
+
+			audioFile.seekg(MSU1.MSU1_AUDIO_POS);
+		}
+		break;
+	case 6:
+		MSU1.MSU1_VOLUME = byte;
+		break;
+	case 7:
+		if (MSU1.MSU1_STATUS & (AudioBusy | AudioError))
+			break;
+
+		MSU1.MSU1_STATUS = (MSU1.MSU1_STATUS & ~0x30) | ((byte & 0x03) << 4);
+
+		if ((byte & (Play | Resume)) == Resume)
+		{
+			MSU1.MSU1_RESUME_TRACK = MSU1.MSU1_CURRENT_TRACK;
+			MSU1.MSU1_RESUME_POS = MSU1.MSU1_AUDIO_POS;
+		}
+		break;
+	}
+}
+
+uint16 S9xMSU1Samples(void)
+{
+	return bufPos - bufBegin;
+}
+
+void S9xMSU1SetOutput(int16 * out, int size)
+{
+	bufPos = bufBegin = out;
+	bufEnd = out + size;
+}
+
+void S9xMSU1PostLoadState(void)
+{
+	if (DataOpen())
+	{
+		dataFile.seekg(MSU1.MSU1_DATA_POS);
+	}
+
+	if (MSU1.MSU1_STATUS & AudioPlaying)
+	{
+		if (AudioOpen())
+		{
+			audioFile.seekg(4);
+			audioFile.read((char *)&audioLoopPos, 4);
+			audioLoopPos = GET_LE32(&audioLoopPos);
+			audioLoopPos <<= 2;
+			audioLoopPos += 8;
+
+			audioFile.seekg(MSU1.MSU1_AUDIO_POS);
+		}
+		else
+		{
+			MSU1.MSU1_STATUS &= ~(AudioPlaying | AudioRepeating);
+			MSU1.MSU1_STATUS |= AudioError;
+		}
+	}
+
+	bufPos = 0;
+	bufBegin = 0;
+	bufEnd = 0;
+
+	partial_samples = 0;
+}
diff --git a/msu1.h b/msu1.h
new file mode 100644
index 00000000..04a22941
--- /dev/null
+++ b/msu1.h
@@ -0,0 +1,239 @@
+/***********************************************************************************
+  Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
+
+  (c) Copyright 1996 - 2002  Gary Henderson (gary.henderson@ntlworld.com),
+                             Jerremy Koot (jkoot@snes9x.com)
+
+  (c) Copyright 2002 - 2004  Matthew Kendora
+
+  (c) Copyright 2002 - 2005  Peter Bortas (peter@bortas.org)
+
+  (c) Copyright 2004 - 2005  Joel Yliluoma (http://iki.fi/bisqwit/)
+
+  (c) Copyright 2001 - 2006  John Weidman (jweidman@slip.net)
+
+  (c) Copyright 2002 - 2006  funkyass (funkyass@spam.shaw.ca),
+                             Kris Bleakley (codeviolation@hotmail.com)
+
+  (c) Copyright 2002 - 2010  Brad Jorsch (anomie@users.sourceforge.net),
+                             Nach (n-a-c-h@users.sourceforge.net),
+
+  (c) Copyright 2002 - 2011  zones (kasumitokoduck@yahoo.com)
+
+  (c) Copyright 2006 - 2007  nitsuja
+
+  (c) Copyright 2009 - 2016  BearOso,
+                             OV2
+
+  (c) Copyright 2011 - 2016  Hans-Kristian Arntzen,
+                             Daniel De Matteis
+                             (Under no circumstances will commercial rights be given)
+
+
+  BS-X C emulator code
+  (c) Copyright 2005 - 2006  Dreamer Nom,
+                             zones
+
+  C4 x86 assembler and some C emulation code
+  (c) Copyright 2000 - 2003  _Demo_ (_demo_@zsnes.com),
+                             Nach,
+                             zsKnight (zsknight@zsnes.com)
+
+  C4 C++ code
+  (c) Copyright 2003 - 2006  Brad Jorsch,
+                             Nach
+
+  DSP-1 emulator code
+  (c) Copyright 1998 - 2006  _Demo_,
+                             Andreas Naive (andreasnaive@gmail.com),
+                             Gary Henderson,
+                             Ivar (ivar@snes9x.com),
+                             John Weidman,
+                             Kris Bleakley,
+                             Matthew Kendora,
+                             Nach,
+                             neviksti (neviksti@hotmail.com)
+
+  DSP-2 emulator code
+  (c) Copyright 2003         John Weidman,
+                             Kris Bleakley,
+                             Lord Nightmare (lord_nightmare@users.sourceforge.net),
+                             Matthew Kendora,
+                             neviksti
+
+  DSP-3 emulator code
+  (c) Copyright 2003 - 2006  John Weidman,
+                             Kris Bleakley,
+                             Lancer,
+                             z80 gaiden
+
+  DSP-4 emulator code
+  (c) Copyright 2004 - 2006  Dreamer Nom,
+                             John Weidman,
+                             Kris Bleakley,
+                             Nach,
+                             z80 gaiden
+
+  OBC1 emulator code
+  (c) Copyright 2001 - 2004  zsKnight,
+                             pagefault (pagefault@zsnes.com),
+                             Kris Bleakley
+                             Ported from x86 assembler to C by sanmaiwashi
+
+  SPC7110 and RTC C++ emulator code used in 1.39-1.51
+  (c) Copyright 2002         Matthew Kendora with research by
+                             zsKnight,
+                             John Weidman,
+                             Dark Force
+
+  SPC7110 and RTC C++ emulator code used in 1.52+
+  (c) Copyright 2009         byuu,
+                             neviksti
+
+  S-DD1 C emulator code
+  (c) Copyright 2003         Brad Jorsch with research by
+                             Andreas Naive,
+                             John Weidman
+
+  S-RTC C emulator code
+  (c) Copyright 2001 - 2006  byuu,
+                             John Weidman
+
+  ST010 C++ emulator code
+  (c) Copyright 2003         Feather,
+                             John Weidman,
+                             Kris Bleakley,
+                             Matthew Kendora
+
+  Super FX x86 assembler emulator code
+  (c) Copyright 1998 - 2003  _Demo_,
+                             pagefault,
+                             zsKnight
+
+  Super FX C emulator code
+  (c) Copyright 1997 - 1999  Ivar,
+                             Gary Henderson,
+                             John Weidman
+
+  Sound emulator code used in 1.5-1.51
+  (c) Copyright 1998 - 2003  Brad Martin
+  (c) Copyright 1998 - 2006  Charles Bilyue'
+
+  Sound emulator code used in 1.52+
+  (c) Copyright 2004 - 2007  Shay Green (gblargg@gmail.com)
+
+  S-SMP emulator code used in 1.54+
+  (c) Copyright 2016         byuu
+
+  SH assembler code partly based on x86 assembler code
+  (c) Copyright 2002 - 2004  Marcus Comstedt (marcus@mc.pp.se)
+
+  2xSaI filter
+  (c) Copyright 1999 - 2001  Derek Liauw Kie Fa
+
+  HQ2x, HQ3x, HQ4x filters
+  (c) Copyright 2003         Maxim Stepin (maxim@hiend3d.com)
+
+  NTSC filter
+  (c) Copyright 2006 - 2007  Shay Green
+
+  GTK+ GUI code
+  (c) Copyright 2004 - 2016  BearOso
+
+  Win32 GUI code
+  (c) Copyright 2003 - 2006  blip,
+                             funkyass,
+                             Matthew Kendora,
+                             Nach,
+                             nitsuja
+  (c) Copyright 2009 - 2016  OV2
+
+  Mac OS GUI code
+  (c) Copyright 1998 - 2001  John Stiles
+  (c) Copyright 2001 - 2011  zones
+
+  Libretro port
+  (c) Copyright 2011 - 2016  Hans-Kristian Arntzen,
+                             Daniel De Matteis
+                             (Under no circumstances will commercial rights be given)
+
+  MSU-1 code
+  (c) Copyright 2016         qwertymodo
+
+
+  Specific ports contains the works of other authors. See headers in
+  individual files.
+
+
+  Snes9x homepage: http://www.snes9x.com/
+
+  Permission to use, copy, modify and/or distribute Snes9x in both binary
+  and source form, for non-commercial purposes, is hereby granted without
+  fee, providing that this license information and copyright notice appear
+  with all copies and any derived work.
+
+  This software is provided 'as-is', without any express or implied
+  warranty. In no event shall the authors be held liable for any damages
+  arising from the use of this software or it's derivatives.
+
+  Snes9x is freeware for PERSONAL USE only. Commercial users should
+  seek permission of the copyright holders first. Commercial use includes,
+  but is not limited to, charging money for Snes9x or software derived from
+  Snes9x, including Snes9x or derivatives in commercial game bundles, and/or
+  using Snes9x as a promotion for your commercial product.
+
+  The copyright holders request that bug fixes and improvements to the code
+  should be forwarded to them so everyone can benefit from the modifications
+  in future versions.
+
+  Super NES and Super Nintendo Entertainment System are trademarks of
+  Nintendo Co., Limited and its subsidiary companies.
+ ***********************************************************************************/
+
+#ifndef _MSU1_H_
+#define _MSU1_H_
+#include "snes9x.h"
+
+struct SMSU1
+{
+	uint8	MSU1_STATUS;
+	uint32	MSU1_DATA_SEEK;
+	uint32	MSU1_DATA_POS;
+	uint16	MSU1_TRACK_SEEK;
+	uint16	MSU1_CURRENT_TRACK;
+	uint32	MSU1_RESUME_TRACK;
+	uint8	MSU1_VOLUME;
+	uint8	MSU1_CONTROL;
+	uint32	MSU1_AUDIO_POS;
+	uint32	MSU1_RESUME_POS;
+};
+
+enum SMSU1_FLAG {
+	Revision		= 0x02,	//max: 0x07
+	AudioResume		= 0x04,
+	AudioError		= 0x08,
+	AudioPlaying		= 0x10,
+	AudioRepeating		= 0x20,
+	AudioBusy		= 0x40,
+	DataBusy		= 0x80
+};
+
+enum SMSU1_CMD {
+	Play			= 0x01,
+	Repeat			= 0x02,
+	Resume			= 0x04
+};
+
+extern struct SMSU1	MSU1;
+
+void S9xResetMSU(void);
+void S9xMSU1Init(void);
+bool S9xMSU1ROMExists(void);
+void S9xMSU1Generate(int sample_count);
+uint8 S9xMSU1ReadPort(int port);
+void S9xMSU1WritePort(int port, uint8 byte);
+uint16 S9xMSU1Samples(void);
+void S9xMSU1SetOutput(int16 *out, int size);
+void S9xMSU1PostLoadState(void);
+
+#endif
diff --git a/port.h b/port.h
index 7a806e69..2378057c 100644
--- a/port.h
+++ b/port.h
@@ -325,7 +325,7 @@ void SetInfoDlgColor(unsigned char, unsigned char, unsigned char);
 #endif  // __WIN32_LIBSNES__
 #endif  // __WIN32__
 
-#ifdef __DJGPP
+#if defined(__DJGPP) || defined(__WIN32__)
 #define SLASH_STR	"\\"
 #define SLASH_CHAR	'\\'
 #else
diff --git a/ppu.cpp b/ppu.cpp
index ebc99ac8..fe0328fa 100644
--- a/ppu.cpp
+++ b/ppu.cpp
@@ -344,6 +344,9 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
 		S9xTraceFormattedMessage("--- HDMA PPU %04X -> %02X", Address, Byte);
 #endif
 
+	if (Settings.MSU1 && (Address & 0xfff8) == 0x2000) // MSU-1
+		S9xMSU1WritePort(Address & 7, Byte);
+	else
 	if ((Address & 0xffc0) == 0x2140) // APUIO0, APUIO1, APUIO2, APUIO3
 		// write_port will run the APU until given clock before writing value
 		S9xAPUWritePort(Address & 3, Byte);
@@ -1095,7 +1098,9 @@ void S9xSetPPU (uint8 Byte, uint16 Address)
 uint8 S9xGetPPU (uint16 Address)
 {
 	// MAP_PPU: $2000-$3FFF
-
+	if (Settings.MSU1 && (Address & 0xfff8) == 0x2000)
+		return (S9xMSU1ReadPort(Address & 7));
+	else
 	if (Address < 0x2100)
 		return (OpenBus);
 
diff --git a/sa1.cpp b/sa1.cpp
index 16f63490..20d45946 100644
--- a/sa1.cpp
+++ b/sa1.cpp
@@ -313,7 +313,16 @@ static void S9xSetSA1MemMap (uint32 which1, uint8 map)
 
 	for (int c = 0; c < 0x100; c += 16)
 	{
-		uint8	*block = &Memory.ROM[(map & 7) * 0x100000 + (c << 12)];
+		uint8 *block;
+		if (Multi.cartType != 5)
+			block = &Memory.ROM[(map & 7) * 0x100000 + (c << 12)];
+		else
+		{
+			if ((map & 7) < 4)
+				block = Memory.ROM + Multi.cartOffsetA + ((map & 7) * 0x100000 + (c << 12));
+			else
+				block = Memory.ROM + Multi.cartOffsetB + (((map & 7) - 4) * 0x100000 + (c << 12));
+		}
 		for (int i = c; i < c + 16; i++)
 			Memory.Map[start  + i] = SA1.Map[start  + i] = block;
 	}
@@ -321,8 +330,26 @@ static void S9xSetSA1MemMap (uint32 which1, uint8 map)
 	for (int c = 0; c < 0x200; c += 16)
 	{
         // conversion to int is needed here - map is promoted but which1 is not
-        int32 offset = (((map & 0x80) ? map : which1) & 7) * 0x100000 + (c << 11) - 0x8000;
-		uint8	*block = &Memory.ROM[offset];
+		int32 offset;
+		uint8 *block;
+		if (Multi.cartType != 5)
+		{
+			offset = (((map & 0x80) ? map : which1) & 7) * 0x100000 + (c << 11) - 0x8000;
+			block = &Memory.ROM[offset];
+		}
+		else
+		{
+			if ((map & 7) < 4)
+			{
+				offset = (((map & 0x80) ? map : which1) & 7) * 0x100000 + (c << 11) - 0x8000;
+				block = Memory.ROM + Multi.cartOffsetA + offset;
+			}
+			else
+			{
+				offset = (((map & 0x80) ? (map - 4) : which1) & 7) * 0x100000 + (c << 11) - 0x8000;
+				block = Memory.ROM + Multi.cartOffsetB + offset;
+			}			
+		}
 		for (int i = c + 8; i < c + 16; i++)
 			Memory.Map[start2 + i] = SA1.Map[start2 + i] = block;
 	}
diff --git a/snapshot.cpp b/snapshot.cpp
index b3dc6ac9..cb6eab29 100644
--- a/snapshot.cpp
+++ b/snapshot.cpp
@@ -1135,6 +1135,23 @@ static FreezeData	SnapBSX[] =
 	ARRAY_ENTRY(6, test2192, 32, uint8_ARRAY_V)
 };
 
+#undef STRUCT
+#define STRUCT	struct SMSU1
+
+static FreezeData	SnapMSU1[] =
+{
+	INT_ENTRY(9, MSU1_STATUS),
+	INT_ENTRY(9, MSU1_DATA_SEEK),
+	INT_ENTRY(9, MSU1_DATA_POS),
+	INT_ENTRY(9, MSU1_TRACK_SEEK),
+	INT_ENTRY(9, MSU1_CURRENT_TRACK),
+	INT_ENTRY(9, MSU1_RESUME_TRACK),
+	INT_ENTRY(9, MSU1_VOLUME),
+	INT_ENTRY(9, MSU1_CONTROL),
+	INT_ENTRY(9, MSU1_AUDIO_POS),
+	INT_ENTRY(9, MSU1_RESUME_POS)
+};
+
 #undef STRUCT
 #define STRUCT	struct SnapshotScreenshotInfo
 
@@ -1306,8 +1323,6 @@ void S9xFreezeToStream (STREAM stream)
 	char	buffer[1024];
 	uint8	*soundsnapshot = new uint8[SPC_SAVE_STATE_BLOCK_SIZE];
 
-	S9xSetSoundMute(TRUE);
-
 	sprintf(buffer, "%s:%04d\n", SNAPSHOT_MAGIC, SNAPSHOT_VERSION);
 	WRITE_STREAM(buffer, strlen(buffer), stream);
 
@@ -1394,6 +1409,9 @@ void S9xFreezeToStream (STREAM stream)
 	if (Settings.BS)
 		FreezeStruct(stream, "BSX", &BSX, SnapBSX, COUNT(SnapBSX));
 
+	if (Settings.MSU1)
+		FreezeStruct(stream, "MSU", &MSU1, SnapMSU1, COUNT(SnapMSU1));
+
 	if (Settings.SnapshotScreenshots)
 	{
 		SnapshotScreenshotInfo	*ssi = new SnapshotScreenshotInfo;
@@ -1443,8 +1461,6 @@ void S9xFreezeToStream (STREAM stream)
 		}
 	}
 
-	S9xSetSoundMute(FALSE);
-
 	delete [] soundsnapshot;
 }
 
@@ -1494,6 +1510,7 @@ int S9xUnfreezeFromStream (STREAM stream)
 	uint8	*local_srtc          = NULL;
 	uint8	*local_rtc_data      = NULL;
 	uint8	*local_bsx_data      = NULL;
+	uint8	*local_msu1_data     = NULL;
 	uint8	*local_screenshot    = NULL;
 	uint8	*local_movie_data    = NULL;
 
@@ -1599,6 +1616,10 @@ int S9xUnfreezeFromStream (STREAM stream)
 		if (result != SUCCESS && Settings.BS)
 			break;
 
+		result = UnfreezeStructCopy(stream, "MSU", &local_msu1_data, SnapMSU1, COUNT(SnapMSU1), version);
+		if (result != SUCCESS && Settings.MSU1)
+			break;
+
 		result = UnfreezeStructCopy(stream, "SHO", &local_screenshot, SnapScreenshot, COUNT(SnapScreenshot), version);
 
 		SnapshotMovieInfo	mi;
@@ -1640,8 +1661,6 @@ int S9xUnfreezeFromStream (STREAM stream)
 		uint32 old_flags     = CPU.Flags;
 		uint32 sa1_old_flags = SA1.Flags;
 
-		S9xSetSoundMute(TRUE);
-
 		S9xReset();
 
 		UnfreezeStructFromCopy(&CPU, SnapCPU, COUNT(SnapCPU), local_cpu, version);
@@ -1717,6 +1736,9 @@ int S9xUnfreezeFromStream (STREAM stream)
 		if (local_bsx_data)
 			UnfreezeStructFromCopy(&BSX, SnapBSX, COUNT(SnapBSX), local_bsx_data, version);
 
+		if (local_msu1_data)
+			UnfreezeStructFromCopy(&MSU1, SnapMSU1, COUNT(SnapMSU1), local_msu1_data, version);
+
 		if (version < SNAPSHOT_VERSION_IRQ)
 		{
 			printf("Converting old snapshot version %d to %d\n...", version, SNAPSHOT_VERSION);
@@ -1798,6 +1820,9 @@ int S9xUnfreezeFromStream (STREAM stream)
 		if (local_bsx_data)
 			S9xBSXPostLoadState();
 
+		if (local_msu1_data)
+			S9xMSU1PostLoadState();
+
 		if (local_movie_data)
 		{
 			// restore last displayed pad_read status
@@ -1867,8 +1892,6 @@ int S9xUnfreezeFromStream (STREAM stream)
 			for (uint32 y = 0; y < (uint32) (IMAGE_HEIGHT); y++)
 				memset(GFX.Screen + y * GFX.RealPPL, 0, GFX.RealPPL * 2);
 		}
-
-		S9xSetSoundMute(FALSE);
 	}
 
 	if (local_cpu)				delete [] local_cpu;
diff --git a/snapshot.h b/snapshot.h
index 33688e88..de45fd66 100644
--- a/snapshot.h
+++ b/snapshot.h
@@ -196,7 +196,7 @@
 #define SNAPSHOT_MAGIC			"#!s9xsnp"
 #define SNAPSHOT_VERSION_IRQ    7
 #define SNAPSHOT_VERSION_BAPU   8
-#define SNAPSHOT_VERSION		8
+#define SNAPSHOT_VERSION		9
 
 #define SUCCESS					1
 #define WRONG_FORMAT			(-1)
diff --git a/snes9x.h b/snes9x.h
index f7bd5740..fbb4cefe 100644
--- a/snes9x.h
+++ b/snes9x.h
@@ -377,6 +377,7 @@ struct SSettings
 	bool8	BS;
 	bool8	BSXItself;
 	bool8	BSXBootup;
+	bool8	MSU1;
 	bool8	MouseMaster;
 	bool8	SuperScopeMaster;
 	bool8	JustifierMaster;
diff --git a/stream.cpp b/stream.cpp
index 37051c32..bb64113d 100644
--- a/stream.cpp
+++ b/stream.cpp
@@ -192,7 +192,11 @@
 
 #include <string>
 #ifdef UNZIP_SUPPORT
-#include "unzip.h"
+#  ifdef SYSTEM_ZIP
+#    include <minizip/unzip.h>
+#  else
+#    include "unzip.h"
+#  endif
 #endif
 #include "snes9x.h"
 #include "stream.h"
diff --git a/stream.h b/stream.h
index b03dea9a..ea22df0a 100644
--- a/stream.h
+++ b/stream.h
@@ -229,8 +229,11 @@ class fStream : public Stream
 };
 
 #ifdef UNZIP_SUPPORT
-
-#include "unzip.h"
+#  ifdef SYSTEM_ZIP
+#    include <minizip/unzip.h>
+#  else
+#    include "unzip.h"
+#  endif
 
 #define unz_BUFFSIZ	1024
 
diff --git a/tile.cpp b/tile.cpp
index 3aae2efe..1bdd7351 100644
--- a/tile.cpp
+++ b/tile.cpp
@@ -1399,29 +1399,12 @@ extern struct SLineMatrixData	LineMatrixData[240];
 //     We don't know how Sub(0, y) is handled.
 
 #define DRAW_PIXEL_H2x1(N, M) \
-    if (Z1 > GFX.DB[Offset + 2 * N] && (M)) \
-    { \
-        GFX.S[Offset + 2 * N] = MATH(GFX.ScreenColors[Pix], GFX.SubScreen[Offset + 2 * N], GFX.SubZBuffer[Offset + 2 * N]); \
-        GFX.S[Offset + 2 * N + 1] = MATH((GFX.ClipColors ? 0 : GFX.SubScreen[Offset + 2 * N + 2]), GFX.RealScreenColors[Pix], GFX.SubZBuffer[Offset + 2 * N]); \
-        GFX.DB[Offset + 2 * N] = GFX.DB[Offset + 2 * N + 1] = Z2; \
-    }
-
-/* The logic above shifts everything one pixel to the left, thus producing a blank line on the right. The code below places the pixel on correct positions but
-   would incur two additional branches for the edges on every pixel.
-*/
-
-//#define DRAW_PIXEL_H2x1(N, M) \
-//    if (Z1 > GFX.DB[Offset + 2 * N] && (M)) \
-//    { \
-//        GFX.S[Offset + 2 * N + 1] = MATH(GFX.ScreenColors[Pix], GFX.SubScreen[Offset + 2 * N], GFX.SubZBuffer[Offset + 2 * N]); \
-//        if ((Offset + 2 * N ) % GFX.RealPPL != (SNES_WIDTH - 1) << 1) \
-//            GFX.S[Offset + 2 * N + 2] = MATH((GFX.ClipColors ? 0 : GFX.SubScreen[Offset + 2 * N + 2]), GFX.RealScreenColors[Pix], GFX.SubZBuffer[Offset + 2 * N]); \
-//        if ((Offset + 2 * N) % GFX.RealPPL == 0) \
-//            GFX.S[Offset + 2 * N] = MATH((GFX.ClipColors ? 0 : GFX.SubScreen[Offset + 2 * N]), GFX.RealScreenColors[Pix], GFX.SubZBuffer[Offset + 2 * N]); \
-//        GFX.DB[Offset + 2 * N] = GFX.DB[Offset + 2 * N + 1] = Z2; \
-//    }
-
-
+	if (Z1 > GFX.DB[Offset + 2 * N] && (M)) \
+	{ \
+		GFX.S[Offset + 2 * N] = MATH((GFX.ClipColors ? 0 : GFX.SubScreen[Offset + 2 * N]), GFX.RealScreenColors[Pix], GFX.SubZBuffer[Offset + 2 * N]); \
+		GFX.S[Offset + 2 * N + 1] = MATH(GFX.ScreenColors[Pix], GFX.SubScreen[Offset + 2 * N], GFX.SubZBuffer[Offset + 2 * N]); \
+		GFX.DB[Offset + 2 * N] = GFX.DB[Offset + 2 * N + 1] = Z2; \
+	}
 
 #define DRAW_PIXEL(N, M)	DRAW_PIXEL_H2x1(N, M)
 #define NAME2				Hires
diff --git a/unix/Makefile.in b/unix/Makefile.in
index 58495689..f0ef47d3 100644
--- a/unix/Makefile.in
+++ b/unix/Makefile.in
@@ -2,12 +2,13 @@
 @S9XNETPLAY@
 @S9XZIP@
 @S9XJMA@
+@S9X_SYSTEM_ZIP@
 
 # Fairly good and special-char-safe descriptor of the os being built on.
 OS         = `uname -s -r -m|sed \"s/ /-/g\"|tr \"[A-Z]\" \"[a-z]\"|tr \"/()\" \"___\"`
 BUILDDIR   = .
 
-OBJECTS    = ../apu/apu.o ../apu/bapu/dsp/sdsp.o ../apu/bapu/dsp/SPC_DSP.o ../apu/bapu/smp/smp.o ../apu/bapu/smp/smp_state.o ../bsx.o ../c4.o ../c4emu.o ../cheats.o ../cheats2.o ../clip.o ../conffile.o ../controls.o ../cpu.o ../cpuexec.o ../cpuops.o ../crosshairs.o ../dma.o ../dsp.o ../dsp1.o ../dsp2.o ../dsp3.o ../dsp4.o ../fxinst.o ../fxemu.o ../gfx.o ../globals.o ../logger.o ../memmap.o ../movie.o ../obc1.o ../ppu.o ../stream.o ../sa1.o ../sa1cpu.o ../screenshot.o ../sdd1.o ../sdd1emu.o ../seta.o ../seta010.o ../seta011.o ../seta018.o ../snapshot.o ../snes9x.o ../spc7110.o ../srtc.o ../tile.o ../filter/2xsai.o ../filter/blit.o ../filter/epx.o ../filter/hq2x.o ../filter/snes_ntsc.o ../statemanager.o unix.o x11.o
+OBJECTS    = ../apu/apu.o ../apu/bapu/dsp/sdsp.o ../apu/bapu/dsp/SPC_DSP.o ../apu/bapu/smp/smp.o ../apu/bapu/smp/smp_state.o ../bsx.o ../c4.o ../c4emu.o ../cheats.o ../cheats2.o ../clip.o ../conffile.o ../controls.o ../cpu.o ../cpuexec.o ../cpuops.o ../crosshairs.o ../dma.o ../dsp.o ../dsp1.o ../dsp2.o ../dsp3.o ../dsp4.o ../fxinst.o ../fxemu.o ../gfx.o ../globals.o ../logger.o ../memmap.o ../msu1.o ../movie.o ../obc1.o ../ppu.o ../stream.o ../sa1.o ../sa1cpu.o ../screenshot.o ../sdd1.o ../sdd1emu.o ../seta.o ../seta010.o ../seta011.o ../seta018.o ../snapshot.o ../snes9x.o ../spc7110.o ../srtc.o ../tile.o ../filter/2xsai.o ../filter/blit.o ../filter/epx.o ../filter/hq2x.o ../filter/snes_ntsc.o ../statemanager.o unix.o x11.o
 DEFS       = -DMITSHM
 
 ifdef S9XDEBUGGER
@@ -19,7 +20,11 @@ OBJECTS   += ../netplay.o ../server.o
 endif
 
 ifdef S9XZIP
-OBJECTS   += ../loadzip.o ../unzip/ioapi.o ../unzip/unzip.o
+OBJECTS   += ../loadzip.o
+ifndef SYSTEM_ZIP
+OBJECTS   += ../unzip/ioapi.o ../unzip/unzip.o
+INCLUDES   = -I../unzip/
+endif
 endif
 
 ifdef S9XJMA
@@ -29,7 +34,7 @@ endif
 CCC        = @CXX@
 CC         = @CC@
 GASM       = @CXX@
-INCLUDES   = -I. -I.. -I../apu/ -I../apu/bapu -I../unzip/ -I../jma/ -I../filter/
+INCLUDES   += -I. -I.. -I../apu/ -I../apu/bapu -I../jma/ -I../filter/
 
 CCFLAGS    = @S9XFLGS@ @S9XDEFS@ $(DEFS)
 CFLAGS     = $(CCFLAGS)
diff --git a/unix/aclocal.m4 b/unix/aclocal.m4
new file mode 100644
index 00000000..2a745e57
--- /dev/null
+++ b/unix/aclocal.m4
@@ -0,0 +1,290 @@
+# generated automatically by aclocal 1.15 -*- Autoconf -*-
+
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+dnl pkg.m4 - Macros to locate and utilise pkg-config.   -*- Autoconf -*-
+dnl serial 11 (pkg-config-0.29.1)
+dnl
+dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+dnl 02111-1307, USA.
+dnl
+dnl As a special exception to the GNU General Public License, if you
+dnl distribute this file as part of a program that contains a
+dnl configuration script generated by Autoconf, you may include it under
+dnl the same distribution terms that you use for the rest of that
+dnl program.
+
+dnl PKG_PREREQ(MIN-VERSION)
+dnl -----------------------
+dnl Since: 0.29
+dnl
+dnl Verify that the version of the pkg-config macros are at least
+dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
+dnl installed version of pkg-config, this checks the developer's version
+dnl of pkg.m4 when generating configure.
+dnl
+dnl To ensure that this macro is defined, also add:
+dnl m4_ifndef([PKG_PREREQ],
+dnl     [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
+dnl
+dnl See the "Since" comment for each macro you use to see what version
+dnl of the macros you require.
+m4_defun([PKG_PREREQ],
+[m4_define([PKG_MACROS_VERSION], [0.29.1])
+m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
+    [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
+])dnl PKG_PREREQ
+
+dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
+dnl ----------------------------------
+dnl Since: 0.16
+dnl
+dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
+dnl first found in the path. Checks that the version of pkg-config found
+dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
+dnl used since that's the first version where most current features of
+dnl pkg-config existed.
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=m4_default([$1], [0.9.0])
+	AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		AC_MSG_RESULT([yes])
+	else
+		AC_MSG_RESULT([no])
+		PKG_CONFIG=""
+	fi
+fi[]dnl
+])dnl PKG_PROG_PKG_CONFIG
+
+dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------------------------------
+dnl Since: 0.18
+dnl
+dnl Check to see whether a particular set of modules exists. Similar to
+dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
+dnl
+dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+dnl only at the first occurence in configure.ac, so if the first place
+dnl it's called might be skipped (such as if it is within an "if", you
+dnl have to call PKG_CHECK_EXISTS manually
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+  m4_default([$2], [:])
+m4_ifvaln([$3], [else
+  $3])dnl
+fi])
+
+dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+dnl ---------------------------------------------
+dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
+dnl pkg_failed based on the result.
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+    pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+    PKG_CHECK_EXISTS([$3],
+                     [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes ],
+		     [pkg_failed=yes])
+ else
+    pkg_failed=untried
+fi[]dnl
+])dnl _PKG_CONFIG
+
+dnl _PKG_SHORT_ERRORS_SUPPORTED
+dnl ---------------------------
+dnl Internal check to see if pkg-config supports short errors.
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi[]dnl
+])dnl _PKG_SHORT_ERRORS_SUPPORTED
+
+
+dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl   [ACTION-IF-NOT-FOUND])
+dnl --------------------------------------------------------------
+dnl Since: 0.4.0
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
+dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+   	AC_MSG_RESULT([no])
+        _PKG_SHORT_ERRORS_SUPPORTED
+        if test $_pkg_short_errors_supported = yes; then
+	        $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
+        else 
+	        $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+	m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])[]dnl
+        ])
+elif test $pkg_failed = untried; then
+     	AC_MSG_RESULT([no])
+	m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
+        ])
+else
+	$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+	$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+        AC_MSG_RESULT([yes])
+	$3
+fi[]dnl
+])dnl PKG_CHECK_MODULES
+
+
+dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+dnl   [ACTION-IF-NOT-FOUND])
+dnl ---------------------------------------------------------------------
+dnl Since: 0.29
+dnl
+dnl Checks for existence of MODULES and gathers its build flags with
+dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
+dnl and VARIABLE-PREFIX_LIBS from --libs.
+dnl
+dnl Note that if there is a possibility the first call to
+dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
+dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
+dnl configure.ac.
+AC_DEFUN([PKG_CHECK_MODULES_STATIC],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+_save_PKG_CONFIG=$PKG_CONFIG
+PKG_CONFIG="$PKG_CONFIG --static"
+PKG_CHECK_MODULES($@)
+PKG_CONFIG=$_save_PKG_CONFIG[]dnl
+])dnl PKG_CHECK_MODULES_STATIC
+
+
+dnl PKG_INSTALLDIR([DIRECTORY])
+dnl -------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable pkgconfigdir as the location where a module
+dnl should install pkg-config .pc files. By default the directory is
+dnl $libdir/pkgconfig, but the default can be changed by passing
+dnl DIRECTORY. The user can override through the --with-pkgconfigdir
+dnl parameter.
+AC_DEFUN([PKG_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([pkgconfigdir],
+    [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
+    [with_pkgconfigdir=]pkg_default)
+AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_INSTALLDIR
+
+
+dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
+dnl --------------------------------
+dnl Since: 0.27
+dnl
+dnl Substitutes the variable noarch_pkgconfigdir as the location where a
+dnl module should install arch-independent pkg-config .pc files. By
+dnl default the directory is $datadir/pkgconfig, but the default can be
+dnl changed by passing DIRECTORY. The user can override through the
+dnl --with-noarch-pkgconfigdir parameter.
+AC_DEFUN([PKG_NOARCH_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([noarch-pkgconfigdir],
+    [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
+    [with_noarch_pkgconfigdir=]pkg_default)
+AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+])dnl PKG_NOARCH_INSTALLDIR
+
+
+dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+dnl -------------------------------------------
+dnl Since: 0.28
+dnl
+dnl Retrieves the value of the pkg-config variable for the given module.
+AC_DEFUN([PKG_CHECK_VAR],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+
+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
+AS_VAR_COPY([$1], [pkg_cv_][$1])
+
+AS_VAR_IF([$1], [""], [$5], [$4])dnl
+])dnl PKG_CHECK_VAR
+
diff --git a/unix/configure b/unix/configure
index 23f99d3e..14be08d5 100755
--- a/unix/configure
+++ b/unix/configure
@@ -622,6 +622,7 @@ ac_includes_default="\
 
 ac_subst_vars='LTLIBOBJS
 LIBOBJS
+S9X_SYSTEM_ZIP
 S9XJMA
 S9XZIP
 S9XNETPLAY
@@ -635,6 +636,11 @@ X_LIBS
 X_PRE_LIBS
 X_CFLAGS
 XMKMF
+SYSTEM_ZIP_LIBS
+SYSTEM_ZIP_CFLAGS
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
 EGREP
 GREP
 CXXCPP
@@ -708,6 +714,7 @@ enable_debugger
 enable_netplay
 enable_gzip
 enable_zip
+with_system_zip
 enable_jma
 enable_screenshot
 with_x
@@ -726,6 +733,11 @@ CXX
 CXXFLAGS
 CCC
 CXXCPP
+PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
+SYSTEM_ZIP_CFLAGS
+SYSTEM_ZIP_LIBS
 XMKMF'
 
 
@@ -1363,6 +1375,7 @@ Optional Features:
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-system-zip       Use system zip (default: check)
   --with-x                use the X Window System
 
 Some influential environment variables:
@@ -1376,6 +1389,15 @@ Some influential environment variables:
   CXX         C++ compiler command
   CXXFLAGS    C++ compiler flags
   CXXCPP      C++ preprocessor
+  PKG_CONFIG  path to pkg-config utility
+  PKG_CONFIG_PATH
+              directories to add to pkg-config's search path
+  PKG_CONFIG_LIBDIR
+              path overriding pkg-config's built-in search path
+  SYSTEM_ZIP_CFLAGS
+              C compiler flags for SYSTEM_ZIP, overriding pkg-config
+  SYSTEM_ZIP_LIBS
+              linker flags for SYSTEM_ZIP, overriding pkg-config
   XMKMF       Path to xmkmf, Makefile generator for X Window System
 
 Use these variables to override the choices made by `configure' or to help
@@ -4831,17 +4853,241 @@ else
 fi
 
 
+S9X_SYSTEM_ZIP="#SYSTEM_ZIP=1"
+
+
+# Check whether --with-system-zip was given.
+if test "${with_system_zip+set}" = set; then :
+  withval=$with_system_zip;
+else
+  with_system_zip="check"
+fi
+
+
 if test "x$enable_zip" = "xyes"; then
-	if test "x$snes9x_cv_zlib" = "xyes"; then
-		S9XZIP="S9XZIP=1"
-		S9XDEFS="$S9XDEFS -DUNZIP_SUPPORT"
-		if test "x$enable_gzip" = "xno"; then
-			S9XLIBS="$S9XLIBS -lz"
-		fi
+	if test "x$with_system_zip" != "xno"; then
+
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=0.9.0
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
 	else
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: zlib not found. Build without ZIP support." >&5
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		PKG_CONFIG=""
+	fi
+fi
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SYSTEM_ZIP" >&5
+$as_echo_n "checking for SYSTEM_ZIP... " >&6; }
+
+if test -n "$SYSTEM_ZIP_CFLAGS"; then
+    pkg_cv_SYSTEM_ZIP_CFLAGS="$SYSTEM_ZIP_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"minizip\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "minizip") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_SYSTEM_ZIP_CFLAGS=`$PKG_CONFIG --cflags "minizip" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$SYSTEM_ZIP_LIBS"; then
+    pkg_cv_SYSTEM_ZIP_LIBS="$SYSTEM_ZIP_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"minizip\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "minizip") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_SYSTEM_ZIP_LIBS=`$PKG_CONFIG --libs "minizip" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        SYSTEM_ZIP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "minizip" 2>&1`
+        else
+	        SYSTEM_ZIP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "minizip" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$SYSTEM_ZIP_PKG_ERRORS" >&5
+
+	if test "x${with_system_zip}" != "xcheck"; then
+				as_fn_error $? "--with-system-zip requested but no proper minizip lib found." "$LINENO" 5
+			else
+				{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: minizip not found. Build without SYSTEM_ZIP support." >&5
+$as_echo "$as_me: WARNING: minizip not found. Build without SYSTEM_ZIP support." >&2;}
+			fi
+
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+	if test "x${with_system_zip}" != "xcheck"; then
+				as_fn_error $? "--with-system-zip requested but no proper minizip lib found." "$LINENO" 5
+			else
+				{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: minizip not found. Build without SYSTEM_ZIP support." >&5
+$as_echo "$as_me: WARNING: minizip not found. Build without SYSTEM_ZIP support." >&2;}
+			fi
+
+else
+	SYSTEM_ZIP_CFLAGS=$pkg_cv_SYSTEM_ZIP_CFLAGS
+	SYSTEM_ZIP_LIBS=$pkg_cv_SYSTEM_ZIP_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	S9XZIP="S9XZIP=1"
+			S9XDEFS="$S9XDEFS -DUNZIP_SUPPORT"
+			S9X_SYSTEM_ZIP="SYSTEM_ZIP=1"
+			S9XLIBS="$S9XLIBS $SYSTEM_ZIP_LIBS"
+			if test "x$enable_gzip" = "xno"; then
+				S9XLIBS="$S9XLIBS -lz"
+			fi
+			S9XDEFS="$S9XDEFS -DSYSTEM_ZIP"
+fi
+	else
+		if test "x$snes9x_cv_zlib" = "xyes"; then
+			S9XZIP="S9XZIP=1"
+			S9XDEFS="$S9XDEFS -DUNZIP_SUPPORT"
+			if test "x$enable_gzip" = "xno"; then
+				S9XLIBS="$S9XLIBS -lz"
+			fi
+		else
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: zlib not found. Build without ZIP support." >&5
 $as_echo "$as_me: WARNING: zlib not found. Build without ZIP support." >&2;}
-		enable_zip="no"
+			enable_zip="no"
+		fi
 	fi
 fi
 
@@ -6068,9 +6314,12 @@ S9XLIBS="$LIBS $S9XLIBS"
 S9XFLGS="`echo \"$S9XFLGS\" | sed -e 's/  */ /g'`"
 S9XDEFS="`echo \"$S9XDEFS\" | sed -e 's/  */ /g'`"
 S9XLIBS="`echo \"$S9XLIBS\" | sed -e 's/  */ /g'`"
+S9X_SYSTEM_ZIP="`echo \"$S9X_SYSTEM_ZIP\" | sed -e 's/  */ /g'`"
 S9XFLGS="`echo \"$S9XFLGS\" | sed -e 's/^  *//'`"
 S9XDEFS="`echo \"$S9XDEFS\" | sed -e 's/^  *//'`"
 S9XLIBS="`echo \"$S9XLIBS\" | sed -e 's/^  *//'`"
+S9X_SYSTEM_ZIP="`echo \"$S9X_SYSTEM_ZIP\" | sed -e 's/^  *//'`"
+
 
 
 
@@ -6100,6 +6349,7 @@ netplay support...... $enable_netplay
 gamepad support...... $enable_gamepad
 GZIP support......... $enable_gzip
 ZIP support.......... $enable_zip
+SYSTEM_ZIP........... $with_system_zip
 JMA support.......... $enable_jma
 debugger............. $enable_debugger
 
diff --git a/unix/configure.ac b/unix/configure.ac
index 3c851dcb..28186c67 100644
--- a/unix/configure.ac
+++ b/unix/configure.ac
@@ -201,16 +201,43 @@ AC_ARG_ENABLE([zip],
 		[enable ZIP support through zlib (default: yes)])],
 	[], [enable_zip="yes"])
 
+S9X_SYSTEM_ZIP="#SYSTEM_ZIP=1"
+
+AC_ARG_WITH([system-zip],
+	[AS_HELP_STRING([--with-system-zip],
+		[Use system zip (default: check)])],
+	[], [with_system_zip="check"])
+
 if test "x$enable_zip" = "xyes"; then
-	if test "x$snes9x_cv_zlib" = "xyes"; then
-		S9XZIP="S9XZIP=1"
-		S9XDEFS="$S9XDEFS -DUNZIP_SUPPORT"
-		if test "x$enable_gzip" = "xno"; then 
-			S9XLIBS="$S9XLIBS -lz"
-		fi
+	if test "x$with_system_zip" != "xno"; then
+		PKG_CHECK_MODULES(
+			SYSTEM_ZIP,
+			minizip,
+			S9XZIP="S9XZIP=1"
+			S9XDEFS="$S9XDEFS -DUNZIP_SUPPORT"
+			S9X_SYSTEM_ZIP="SYSTEM_ZIP=1"
+			S9XLIBS="$S9XLIBS $SYSTEM_ZIP_LIBS"
+			if test "x$enable_gzip" = "xno"; then
+				S9XLIBS="$S9XLIBS -lz"
+			fi
+			S9XDEFS="$S9XDEFS -DSYSTEM_ZIP",
+			if test "x${with_system_zip}" != "xcheck"; then
+				AC_MSG_ERROR([--with-system-zip requested but no proper minizip lib found.])
+			else
+				AC_MSG_WARN([minizip not found. Build without SYSTEM_ZIP support.])
+			fi
+		)
 	else
-		AC_MSG_WARN([zlib not found. Build without ZIP support.])
-		enable_zip="no"
+		if test "x$snes9x_cv_zlib" = "xyes"; then
+			S9XZIP="S9XZIP=1"
+			S9XDEFS="$S9XDEFS -DUNZIP_SUPPORT"
+			if test "x$enable_gzip" = "xno"; then
+				S9XLIBS="$S9XLIBS -lz"
+			fi
+		else
+			AC_MSG_WARN([zlib not found. Build without ZIP support.])
+			enable_zip="no"
+		fi
 	fi
 fi
 
@@ -427,9 +454,11 @@ S9XLIBS="$LIBS $S9XLIBS"
 S9XFLGS="`echo \"$S9XFLGS\" | sed -e 's/  */ /g'`"
 S9XDEFS="`echo \"$S9XDEFS\" | sed -e 's/  */ /g'`"
 S9XLIBS="`echo \"$S9XLIBS\" | sed -e 's/  */ /g'`"
+S9X_SYSTEM_ZIP="`echo \"$S9X_SYSTEM_ZIP\" | sed -e 's/  */ /g'`"
 S9XFLGS="`echo \"$S9XFLGS\" | sed -e 's/^  *//'`"
 S9XDEFS="`echo \"$S9XDEFS\" | sed -e 's/^  *//'`"
 S9XLIBS="`echo \"$S9XLIBS\" | sed -e 's/^  *//'`"
+S9X_SYSTEM_ZIP="`echo \"$S9X_SYSTEM_ZIP\" | sed -e 's/^  *//'`"
 
 AC_SUBST(S9XFLGS)
 AC_SUBST(S9XDEFS)
@@ -439,6 +468,7 @@ AC_SUBST(S9XDEBUGGER)
 AC_SUBST(S9XNETPLAY)
 AC_SUBST(S9XZIP)
 AC_SUBST(S9XJMA)
+AC_SUBST(S9X_SYSTEM_ZIP)
 
 rm config.info 2>/dev/null
 
@@ -459,6 +489,7 @@ netplay support...... $enable_netplay
 gamepad support...... $enable_gamepad
 GZIP support......... $enable_gzip
 ZIP support.......... $enable_zip
+SYSTEM_ZIP........... $with_system_zip
 JMA support.......... $enable_jma
 debugger............. $enable_debugger
 
diff --git a/win32/CD3DCG.cpp b/win32/CD3DCG.cpp
index d5458cb6..95b61b5f 100644
--- a/win32/CD3DCG.cpp
+++ b/win32/CD3DCG.cpp
@@ -383,7 +383,7 @@ bool CD3DCG::LoadShader(const TCHAR *shaderFile)
 		hr = pDevice->CreateVertexBuffer(sizeof(VERTEX)*4,D3DUSAGE_WRITEONLY,0,D3DPOOL_MANAGED,&pass.vertexBuffer,NULL);
 		if(FAILED(hr)) {
 			pass.vertexBuffer = NULL;
-			DXTRACE_ERR_MSGBOX(TEXT("Error creating vertex buffer"), hr);
+			DXTRACE_ERR_MSGBOX(L"Error creating vertex buffer", hr);
 			return false;
 		}
 
@@ -449,7 +449,7 @@ void CD3DCG::ensureTextureSize(LPDIRECT3DTEXTURE9 &tex, D3DXVECTOR2 &texSize,
 		texSize = wantedSize;
 
 		if(FAILED(hr)) {
-			DXTRACE_ERR_MSGBOX(TEXT("Error while creating texture"), hr);
+			DXTRACE_ERR_MSGBOX(L"Error while creating texture", hr);
 			return;
 		}
 	}
@@ -860,7 +860,7 @@ void CD3DCG::setupVertexDeclaration(shaderPass &pass)
 	LPDIRECT3DVERTEXDECLARATION9 vertexDeclaration;
 	HRESULT hr = pDevice->CreateVertexDeclaration(vElems,&vertexDeclaration);
 	if(FAILED(hr)) {
-		DXTRACE_ERR_MSGBOX(TEXT("Error creating vertex declaration"), hr);
+		DXTRACE_ERR_MSGBOX(L"Error creating vertex declaration", hr);
 	}
 	if(pass.vertexDeclaration)
 		pass.vertexDeclaration->Release();
diff --git a/win32/CDirect3D.cpp b/win32/CDirect3D.cpp
index 1c69d49d..7fd8d6eb 100644
--- a/win32/CDirect3D.cpp
+++ b/win32/CDirect3D.cpp
@@ -272,7 +272,7 @@ bool CDirect3D::Initialize(HWND hWnd)
 
 	pD3D = Direct3DCreate9(D3D_SDK_VERSION);
 	if(pD3D == NULL) {
-		DXTRACE_ERR_MSGBOX(TEXT("Error creating initial D3D9 object"), 0);
+		DXTRACE_ERR_MSGBOX(L"Error creating initial D3D9 object", 0);
 		return false;
 	}
 
@@ -290,19 +290,19 @@ bool CDirect3D::Initialize(HWND hWnd)
 					  &dPresentParams,
                       &pDevice);
 	if(FAILED(hr)) {
-		DXTRACE_ERR_MSGBOX(TEXT("Error creating D3D9 device"), hr);
+		DXTRACE_ERR_MSGBOX(L"Error creating D3D9 device", hr);
 		return false;
 	}
 
 	hr = pDevice->CreateVertexBuffer(sizeof(vertexStream),D3DUSAGE_WRITEONLY,0,D3DPOOL_MANAGED,&vertexBuffer,NULL);
 	if(FAILED(hr)) {
-		DXTRACE_ERR_MSGBOX(TEXT("Error creating vertex buffer"), hr);
+		DXTRACE_ERR_MSGBOX(L"Error creating vertex buffer", hr);
 		return false;
 	}
 
 	hr = pDevice->CreateVertexDeclaration(vertexElems,&vertexDeclaration);
 	if(FAILED(hr)) {
-		DXTRACE_ERR_MSGBOX(TEXT("Error creating vertex declaration"), hr);
+		DXTRACE_ERR_MSGBOX(L"Error creating vertex declaration", hr);
 		return false;
 	}
 
@@ -312,7 +312,7 @@ bool CDirect3D::Initialize(HWND hWnd)
 		cgContext = cgCreateContext();
 		hr = cgD3D9SetDevice(pDevice);
 		if(FAILED(hr)) {
-			DXTRACE_ERR_MSGBOX(TEXT("Error setting cg device"), hr);
+			DXTRACE_ERR_MSGBOX(L"Error setting cg device", hr);
 		}
 		cgShader = new CD3DCG(cgContext,pDevice);
 	}
@@ -650,14 +650,14 @@ void CDirect3D::Render(SSurface Src)
 				ResetDevice();
 				return;
 			default:
-				DXTRACE_ERR_MSGBOX( TEXT("Internal driver error"), hr);
+				DXTRACE_ERR_MSGBOX( L"Internal driver error", hr);
 				return;
 		}
 	}
 
 	//BlankTexture(drawSurface);
 	if(FAILED(hr = drawSurface->LockRect(0, &lr, NULL, 0))) {
-		DXTRACE_ERR_MSGBOX( TEXT("Unable to lock texture"), hr);
+		DXTRACE_ERR_MSGBOX( L"Unable to lock texture", hr);
 		return;
 	} else {
 		Dst.Surface = (unsigned char *)lr.pBits;
@@ -757,7 +757,7 @@ void CDirect3D::CreateDrawSurface()
 			NULL );
 
 		if(FAILED(hr)) {
-			DXTRACE_ERR_MSGBOX(TEXT("Error while creating texture"), hr);
+			DXTRACE_ERR_MSGBOX(L"Error while creating texture", hr);
 			return;
 		}
 	}
@@ -787,7 +787,7 @@ bool CDirect3D::BlankTexture(LPDIRECT3DTEXTURE9 texture)
 	HRESULT hr;
 
 	if(FAILED(hr = texture->LockRect(0, &lr, NULL, 0))) {
-		DXTRACE_ERR_MSGBOX( TEXT("Unable to lock texture"), hr);
+		DXTRACE_ERR_MSGBOX( L"Unable to lock texture", hr);
 		return false;
 	} else {
 		memset(lr.pBits, 0, lr.Pitch * quadTextureSize);
@@ -938,7 +938,7 @@ bool CDirect3D::ResetDevice()
 	}
 
 	if(FAILED(hr = pDevice->Reset(&dPresentParams))) {
-		DXTRACE_ERR(TEXT("Unable to reset device"), hr);
+		DXTRACE_ERR(L"Unable to reset device", hr);
 		return false;
 	}
 
diff --git a/win32/CDirectSound.cpp b/win32/CDirectSound.cpp
index 192f348e..01f19b06 100644
--- a/win32/CDirectSound.cpp
+++ b/win32/CDirectSound.cpp
@@ -314,7 +314,8 @@ bool CDirectSound::InitSoundBuffer()
 	blockCount = 4;
 	blockTime = GUI.SoundBufferSize / blockCount;
 
-	blockSamples = (Settings.SoundPlaybackRate * blockTime * (Settings.Stereo ? 2 : 1)) / 1000;
+	blockSamples = (Settings.SoundPlaybackRate * blockTime) / 1000;
+    blockSamples *= (Settings.Stereo ? 2 : 1);
 	blockSize = blockSamples * (Settings.SixteenBitSound ? 2 : 1);
 	bufferSize = blockSize * blockCount;
 
diff --git a/win32/CXAudio2.cpp b/win32/CXAudio2.cpp
index fa54ae00..7bfdb6ef 100644
--- a/win32/CXAudio2.cpp
+++ b/win32/CXAudio2.cpp
@@ -234,7 +234,7 @@ bool CXAudio2::InitXAudio2(void)
 
 	HRESULT hr;
 	if ( FAILED(hr = XAudio2Create( &pXAudio2, 0 , XAUDIO2_DEFAULT_PROCESSOR ) ) ) {
-		DXTRACE_ERR_MSGBOX(TEXT("Unable to create XAudio2 object."),hr);
+		DXTRACE_ERR_MSGBOX(L"Unable to create XAudio2 object.",hr);
 		MessageBox (GUI.hWnd, TEXT("\
 Unable to initialize XAudio2. You will not be able to hear any\n\
 sound effects or music while playing.\n\n\
@@ -257,7 +257,7 @@ bool CXAudio2::InitVoices(void)
 	HRESULT hr;
 	if ( FAILED(hr = pXAudio2->CreateMasteringVoice( &pMasterVoice, (Settings.Stereo?2:1),
 		Settings.SoundPlaybackRate, 0, 0 , NULL ) ) ) {
-			DXTRACE_ERR_MSGBOX(TEXT("Unable to create mastering voice."),hr);
+			DXTRACE_ERR_MSGBOX(L"Unable to create mastering voice.",hr);
 			return false;
 	}
 
@@ -272,7 +272,7 @@ bool CXAudio2::InitVoices(void)
 
 	if( FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wfx,
 		XAUDIO2_VOICE_NOSRC , XAUDIO2_DEFAULT_FREQ_RATIO, this, NULL, NULL ) ) ) {
-			DXTRACE_ERR_MSGBOX(TEXT("Unable to create source voice."),hr);
+			DXTRACE_ERR_MSGBOX(L"Unable to create source voice.",hr);
 			return false;
 	}
 
@@ -355,7 +355,8 @@ bool CXAudio2::SetupSound()
 	blockCount = 8;
 	UINT32 blockTime = GUI.SoundBufferSize / blockCount;
 
-	singleBufferSamples = (Settings.SoundPlaybackRate * blockTime * (Settings.Stereo ? 2 : 1)) / 1000;
+	singleBufferSamples = (Settings.SoundPlaybackRate * blockTime) / 1000;
+    singleBufferSamples *= (Settings.Stereo ? 2 : 1);
 	singleBufferBytes = singleBufferSamples * (Settings.SixteenBitSound ? 2 : 1);
 	sum_bufferSize = singleBufferBytes * blockCount;
 
diff --git a/win32/InputCustom.cpp b/win32/InputCustom.cpp
index c0dc1446..e2b2767d 100644
--- a/win32/InputCustom.cpp
+++ b/win32/InputCustom.cpp
@@ -959,17 +959,36 @@ static LRESULT CALLBACK InputCustomWndProc(HWND hwnd, UINT msg, WPARAM wParam, L
 		return 1;
 	case WM_USER+45:
 	case WM_KEYDOWN:
-		TranslateKey(wParam,temp);
-		col = CheckButtonKey(wParam);
+    {
+        UINT scancode = (lParam & 0x00ff0000) >> 16;
+        int extended = (lParam & 0x01000000) != 0;
 
-		icp->crForeGnd = ((~col) & 0x00ffffff);
-		icp->crBackGnd = col;
-		SetWindowText(hwnd,_tFromChar(temp));
-		InvalidateRect(icp->hwnd, NULL, FALSE);
-		UpdateWindow(icp->hwnd);
-		SendMessage(pappy,WM_USER+43,wParam,(LPARAM)hwnd);
+        switch (wParam) {
+        case VK_SHIFT:
+            wParam = MapVirtualKey(scancode, MAPVK_VSC_TO_VK_EX);
+            break;
+        case VK_CONTROL:
+            wParam = extended ? VK_RCONTROL : VK_LCONTROL;
+            break;
+        case VK_MENU:
+            wParam = extended ? VK_RMENU : VK_LMENU;
+            break;
+        default:
+            break;
+        }
 
-		break;
+        TranslateKey(wParam, temp);
+        col = CheckButtonKey(wParam);
+
+        icp->crForeGnd = ((~col) & 0x00ffffff);
+        icp->crBackGnd = col;
+        SetWindowText(hwnd, _tFromChar(temp));
+        InvalidateRect(icp->hwnd, NULL, FALSE);
+        UpdateWindow(icp->hwnd);
+        SendMessage(pappy, WM_USER + 43, wParam, (LPARAM)hwnd);
+
+        break;
+    }
 	case WM_USER+44:
 
 		TranslateKey(wParam,temp);
diff --git a/win32/rsrc/resource.h b/win32/rsrc/resource.h
index 0f6bf528..07ec2620 100644
--- a/win32/rsrc/resource.h
+++ b/win32/rsrc/resource.h
@@ -496,13 +496,14 @@
 #define ID_WINDOW_SIZE_4X               40172
 #define ID_DEBUG_APU_TRACE              40173
 #define ID_EMULATION_BACKGROUNDINPUT    40174
+#define ID_SAVEMEMPACK                  40175
 
 // Next default values for new objects
 // 
 #ifdef APSTUDIO_INVOKED
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        151
-#define _APS_NEXT_COMMAND_VALUE         40175
+#define _APS_NEXT_COMMAND_VALUE         40176
 #define _APS_NEXT_CONTROL_VALUE         3018
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
diff --git a/win32/rsrc/snes9x.rc b/win32/rsrc/snes9x.rc
index 5c11c0a3..0629f188 100644
--- a/win32/rsrc/snes9x.rc
+++ b/win32/rsrc/snes9x.rc
@@ -716,14 +716,15 @@ IDB_HIDDENFOLDER        BITMAP                  "hiddir.bmp"
 // remains consistent on all systems.
 IDI_ICON1               ICON                    "icon1.ico"
 
+
 /////////////////////////////////////////////////////////////////////////////
 //
 // Version
 //
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,5,3,0
- PRODUCTVERSION 1,5,3,0
+ FILEVERSION 1,5,4,1
+ PRODUCTVERSION 1,5,4,1
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -822,6 +823,7 @@ BEGIN
             MENUITEM "S&ave SPC Data",              ID_FILE_SAVE_SPC_DATA
             MENUITEM "Save Screenshot",             ID_SAVESCREENSHOT
             MENUITEM "Sa&ve S-RAM Data",            ID_FILE_SAVE_SRAM_DATA
+	        MENUITEM "Save Memory Pack",            ID_SAVEMEMPACK
         END
         MENUITEM "ROM Information...",          IDM_ROM_INFO
         MENUITEM SEPARATOR
diff --git a/win32/snes9xw.vcxproj b/win32/snes9xw.vcxproj
index 31b00270..ad885fcc 100644
--- a/win32/snes9xw.vcxproj
+++ b/win32/snes9xw.vcxproj
@@ -677,6 +677,7 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </CustomBuild>
+    <ClInclude Include="..\msu1.h" />
     <ClInclude Include="..\statemanager.h" />
     <CustomBuild Include="..\stream.h" />
     <CustomBuild Include="..\tile.h" />
@@ -777,6 +778,7 @@
     <ClCompile Include="..\logger.cpp" />
     <ClCompile Include="..\memmap.cpp" />
     <ClCompile Include="..\movie.cpp" />
+    <ClCompile Include="..\msu1.cpp" />
     <ClCompile Include="..\netplay.cpp" />
     <ClCompile Include="..\obc1.cpp" />
     <ClCompile Include="..\ppu.cpp" />
diff --git a/win32/snes9xw.vcxproj.filters b/win32/snes9xw.vcxproj.filters
index d2279054..8020f00f 100644
--- a/win32/snes9xw.vcxproj.filters
+++ b/win32/snes9xw.vcxproj.filters
@@ -243,6 +243,9 @@
     <ClInclude Include="dxerr.h">
       <Filter>GUI</Filter>
     </ClInclude>
+    <ClInclude Include="..\msu1.h">
+      <Filter>APU</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\bsx.cpp">
@@ -539,6 +542,9 @@
     <ClCompile Include="dxerr.cpp">
       <Filter>GUI</Filter>
     </ClCompile>
+    <ClCompile Include="..\msu1.cpp">
+      <Filter>APU</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <None Include="rsrc\nodrop.cur">
diff --git a/win32/wlanguage.h b/win32/wlanguage.h
index 2c68bede..50735f57 100644
--- a/win32/wlanguage.h
+++ b/win32/wlanguage.h
@@ -597,6 +597,8 @@ Nintendo is a trade mark.")
 
 #define INFO_SAVE_SPC "Saving SPC Data."
 
+#define MPAK_SAVE_FAILED "Failed to save Memory Pack."
+
 #define CHEATS_INFO_ENABLED "Cheats enabled."
 #define CHEATS_INFO_DISABLED "Cheats disabled."
 #define CHEATS_INFO_ENABLED_NONE "Cheats enabled. (None are active.)"
diff --git a/win32/wsnes9x.cpp b/win32/wsnes9x.cpp
index 8a303486..b4de0412 100644
--- a/win32/wsnes9x.cpp
+++ b/win32/wsnes9x.cpp
@@ -2016,7 +2016,7 @@ LRESULT CALLBACK WinProc(
 				{
 					char localhostname [256];
 					gethostname(localhostname,256);
-					_stprintf(localhostmsg, TEXT("Your host name is: %s\nYour port number is: %d"), _tFromChar(localhostname), Settings.Port);
+					_stprintf(localhostmsg, TEXT("Your host name is: %s\nYour port number is: %d"), (TCHAR *)_tFromChar(localhostname), Settings.Port);
 					MessageBox(GUI.hWnd,localhostmsg,TEXT("Note"),MB_OK);
 				}
 			}
@@ -2248,6 +2248,17 @@ LRESULT CALLBACK WinProc(
 			if(!success)
 				S9xMessage(S9X_ERROR, S9X_FREEZE_FILE_INFO, SRM_SAVE_FAILED);
 		}	break;
+		case ID_SAVEMEMPACK: {
+			const char *filename = S9xGetFilenameInc(".bs", SRAM_DIR);
+			bool8 success = Memory.SaveMPAK(filename);
+			if (!success)
+				S9xMessage(S9X_ERROR, 0, MPAK_SAVE_FAILED);
+			else
+			{
+				sprintf(String, "Saved Memory Pack %s", filename);
+				S9xMessage(S9X_INFO, 0, String);
+			}
+		}	break;
 		case ID_FILE_RESET:
 #ifdef NETPLAY_SUPPORT
 			if (Settings.NetPlayServer)
@@ -2423,7 +2434,7 @@ LRESULT CALLBACK WinProc(
 					{
 
 						if (!LoadROM(GUI.RecentGames [i])) {
-							sprintf (String, ERR_ROM_NOT_FOUND, _tToChar(GUI.RecentGames [i]));
+							sprintf (String, ERR_ROM_NOT_FOUND, (char *)_tToChar(GUI.RecentGames [i]));
 							S9xMessage (S9X_ERROR, S9X_ROM_NOT_FOUND, String);
 							S9xRemoveFromRecentGames(i);
 						}
@@ -2694,7 +2705,7 @@ LRESULT CALLBACK WinProc(
 		{
 			TCHAR buf [NP_MAX_ACTION_LEN + 10];
 
-			_stprintf (buf, TEXT("%s %3d%%"), _tFromChar(NetPlay.ActionMsg), (int) lParam);
+			_stprintf (buf, TEXT("%s %3d%%"), (TCHAR *)_tFromChar(NetPlay.ActionMsg), (int) lParam);
 			SetWindowText (GUI.hWnd, buf);
 		}
 #if 0
@@ -3693,7 +3704,7 @@ loop_exit:
 
 void FreezeUnfreeze (int slot, bool8 freeze)
 {
-    const char *filename;
+    char filename[_MAX_PATH +1];
     char ext [_MAX_EXT + 1];
 
 #ifdef NETPLAY_SUPPORT
@@ -3706,7 +3717,7 @@ void FreezeUnfreeze (int slot, bool8 freeze)
 #endif
 
 	snprintf(ext, _MAX_EXT, ".%03d", slot);
-	filename = S9xGetFilename(ext,SNAPSHOT_DIR);
+	strcpy(filename, S9xGetFilename(ext, SNAPSHOT_DIR));
 
     S9xSetPause (PAUSE_FREEZE_FILE);
 
@@ -5015,7 +5026,7 @@ INT_PTR CALLBACK DlgInfoProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 				{
 					SetTextColor((HDC)wParam, GUI.InfoColor);
 					SetBkColor((HDC)wParam, RGB(0,0,0));
-					return (BOOL)GetStockObject( BLACK_BRUSH );
+					return (INT_PTR)GetStockObject( BLACK_BRUSH );
 				}
 				break;
 			case WM_PAINT:
@@ -5309,7 +5320,7 @@ void rominfo(const TCHAR *filename, TCHAR *namebuffer, TCHAR *sizebuffer)
 	lstrcpy(namebuffer, ROM_ITEM_DESCNOTAVAILABLE);
 	lstrcpy(sizebuffer, TEXT("? Mbits"));
 
-#ifdef ZLIB
+#ifdef UNZIP_SUPPORT
 	if(IsCompressed(filename))
 	{
 		unzFile uf = unzOpen(_tToChar(filename));
@@ -7006,6 +7017,7 @@ void MakeExtFile(void)
 
 	out<<"smcN"<<endl<<"zipY"<<endl<<"gzY" <<endl<<"swcN"<<endl<<"figN"<<endl;
 	out<<"sfcN"<<endl;
+	out<<"bsN"<<endl;
 	out<<"jmaY";
 	out.close();
 	SetFileAttributes(TEXT("Valid.Ext"), FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_READONLY);
@@ -10429,7 +10441,7 @@ static void set_movieinfo(const TCHAR* path, HWND hDlg)
 
 			if(m.SyncFlags & MOVIE_SYNC_HASROMINFO)
 			{
-				_stprintf(str, MOVIE_INFO_MOVIEROM MOVIE_INFO_ROMINFO, m.ROMCRC32, _tFromChar(m.ROMName));
+				_stprintf(str, MOVIE_INFO_MOVIEROM MOVIE_INFO_ROMINFO, m.ROMCRC32, (TCHAR *)_tFromChar(m.ROMName));
 				SetWindowText(GetDlgItem(hDlg, IDC_MOVIEROMINFO), str);
 			}
 			else
@@ -10439,7 +10451,7 @@ static void set_movieinfo(const TCHAR* path, HWND hDlg)
 			}
 
 			bool mismatch = (m.SyncFlags & MOVIE_SYNC_HASROMINFO) && m.ROMCRC32 != Memory.ROMCRC32;
-			_stprintf(str, MOVIE_INFO_CURRENTROM MOVIE_INFO_ROMINFO TEXT("%s"), Memory.ROMCRC32, _tFromChar(Memory.ROMName), mismatch?MOVIE_INFO_MISMATCH:TEXT(""));
+			_stprintf(str, MOVIE_INFO_CURRENTROM MOVIE_INFO_ROMINFO TEXT("%s"), Memory.ROMCRC32, (TCHAR *)_tFromChar(Memory.ROMName), mismatch?MOVIE_INFO_MISMATCH:TEXT(""));
 			SetWindowText(GetDlgItem(hDlg, IDC_CURRENTROMINFO), str);
 
 			_stprintf(str, TEXT("%s"), mismatch?MOVIE_WARNING_MISMATCH:MOVIE_WARNING_OK);
@@ -10505,7 +10517,7 @@ static void set_movieinfo(const TCHAR* path, HWND hDlg)
 			// no movie loaded
 			SetWindowText(GetDlgItem(hDlg, IDC_MOVIEROMINFO), dirStr);
 
-			_stprintf(str, MOVIE_INFO_CURRENTROM MOVIE_INFO_ROMINFO, Memory.ROMCRC32, _tFromChar(Memory.ROMName));
+			_stprintf(str, MOVIE_INFO_CURRENTROM MOVIE_INFO_ROMINFO, Memory.ROMCRC32, (TCHAR *)_tFromChar(Memory.ROMName));
 			SetWindowText(GetDlgItem(hDlg, IDC_CURRENTROMINFO), str);
 		}