diff --git a/src/boards/28.cpp b/src/boards/28.cpp
new file mode 100644
index 00000000..67053302
--- /dev/null
+++ b/src/boards/28.cpp
@@ -0,0 +1,217 @@
+/*
+ Copyright (C) 2012 FCEUX team
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the this software. If not, see .
+*/
+
+#include "mapinc.h"
+
+// http://wiki.nesdev.com/w/index.php/INES_Mapper_028
+
+//config
+static int prg_mask_16k;
+
+// state
+uint8 reg;
+uint8 chr;
+uint8 prg;
+uint8 mode;
+uint8 outer;
+
+void SyncMirror()
+{
+ switch (mode & 3)
+ {
+ case 0: setmirror(MI_0); break;
+ case 1: setmirror(MI_1); break;
+ case 2: setmirror(MI_V); break;
+ case 3: setmirror(MI_H); break;
+ }
+}
+
+void Mirror(uint8 value)
+{
+ if ((mode & 2) == 0)
+ {
+ mode &= 0xfe;
+ mode |= value >> 4 & 1;
+ }
+ SyncMirror();
+}
+
+
+static void Sync()
+{
+ int prglo;
+ int prghi;
+
+ int outb = outer << 1;
+ //this can probably be rolled up, but i have no motivation to do so
+ //until it's been tested
+ switch (mode & 0x3c)
+ {
+ //32K modes
+ case 0x00:
+ case 0x04:
+ prglo = outb;
+ prghi = outb | 1;
+ break;
+ case 0x10:
+ case 0x14:
+ prglo = outb & ~2 | prg << 1 & 2;
+ prghi = outb & ~2 | prg << 1 & 2 | 1;
+ break;
+ case 0x20:
+ case 0x24:
+ prglo = outb & ~6 | prg << 1 & 6;
+ prghi = outb & ~6 | prg << 1 & 6 | 1;
+ break;
+ case 0x30:
+ case 0x34:
+ prglo = outb & ~14 | prg << 1 & 14;
+ prghi = outb & ~14 | prg << 1 & 14 | 1;
+ break;
+ //bottom fixed modes
+ case 0x08:
+ prglo = outb;
+ prghi = outb | prg & 1;
+ break;
+ case 0x18:
+ prglo = outb;
+ prghi = outb & ~2 | prg & 3;
+ break;
+ case 0x28:
+ prglo = outb;
+ prghi = outb & ~6 | prg & 7;
+ break;
+ case 0x38:
+ prglo = outb;
+ prghi = outb & ~14 | prg & 15;
+ break;
+ //top fixed modes
+ case 0x0c:
+ prglo = outb | prg & 1;
+ prghi = outb | 1;
+ break;
+ case 0x1c:
+ prglo = outb & ~2 | prg & 3;
+ prghi = outb | 1;
+ break;
+ case 0x2c:
+ prglo = outb & ~6 | prg & 7;
+ prghi = outb | 1;
+ break;
+ case 0x3c:
+ prglo = outb & ~14 | prg & 15;
+ prghi = outb | 1;
+ break;
+ }
+ prglo &= prg_mask_16k;
+ prghi &= prg_mask_16k;
+
+ setprg16(0x8000, prglo);
+ setprg16(0xC000, prghi);
+ setchr8(chr);
+}
+
+static DECLFW(WriteEXP)
+{
+ uint32 addr = A;
+ uint8 value = V;
+ if (addr >= 05000)
+ reg = value & 0x81;
+}
+
+static DECLFW(WritePRG)
+{
+ uint32 addr = A;
+ uint8 value = V;
+ switch (reg)
+ {
+ case 0x00:
+ chr = value & 3;
+ Mirror(value);
+ break;
+ case 0x01:
+ prg = value & 15;
+ Mirror(value);
+ Sync();
+ break;
+ case 0x80:
+ mode = value & 63;
+ SyncMirror();
+ Sync();
+ break;
+ case 0x81:
+ outer = value & 63;
+ Sync();
+ break;
+ }
+}
+
+
+
+static void M28Reset(void)
+{
+ outer = 63;
+ prg = 15;
+ Sync();
+}
+
+
+static void M28Power(void)
+{
+ prg_mask_16k = PRGsize[0] - 1;
+
+ //EXP
+ SetWriteHandler(0x4020,0x5FFF,WriteEXP);
+
+ //PRG
+ SetWriteHandler(0x8000,0xFFFF,WritePRG);
+ SetReadHandler(0x8000,0xFFFF,CartBR);
+
+ //WRAM
+ SetReadHandler(0x6000,0x7FFF,CartBR);
+ SetWriteHandler(0x6000,0x7FFF,CartBW);
+
+ M28Reset();
+}
+
+static void M28Close(void)
+{
+}
+
+static SFORMAT StateRegs[]=
+{
+ {®, 1, "REG"},
+ {&chr, 1, "CHR"},
+ {&prg, 1, "PRG"},
+ {&mode, 1, "MODE"},
+ {&outer, 1, "OUTR"},
+ {0}
+};
+
+static void StateRestore(int version)
+{
+ Sync();
+}
+
+void Mapper28_Init(CartInfo* info)
+{
+ info->Power=M28Power;
+ info->Reset=M28Reset;
+ info->Close=M28Close;
+ GameStateRestore=StateRestore;
+ AddExState(&StateRegs, ~0, 0, 0);
+}
diff --git a/src/boards/SConscript b/src/boards/SConscript
index 4c3fb14c..0cc186a8 100644
--- a/src/boards/SConscript
+++ b/src/boards/SConscript
@@ -41,6 +41,7 @@ my_list = Split("""
246.cpp
252.cpp
253.cpp
+28.cpp
32.cpp
33.cpp
34.cpp
diff --git a/src/ines.cpp b/src/ines.cpp
index e273c381..ca9a42fb 100644
--- a/src/ines.cpp
+++ b/src/ines.cpp
@@ -551,7 +551,7 @@ static BMAPPINGLocal bmap[] = {
{"Konami VRC2/VRC4", 25, Mapper25_Init},
// {"", 26, Mapper26_Init},
// {"", 27, Mapper27_Init}, // Deprecated, dupe for VRC2/VRC4 mapper
-// {"", 28, Mapper28_Init},
+ {"INL-ROM", 28, Mapper28_Init},
// {"", 29, Mapper29_Init},
// {"", 30, Mapper30_Init},
// {"", 31, Mapper31_Init},
diff --git a/src/ines.h b/src/ines.h
index 6c7407cc..d3acc83f 100644
--- a/src/ines.h
+++ b/src/ines.h
@@ -382,6 +382,7 @@ void Mapper21_Init(CartInfo *);
void Mapper22_Init(CartInfo *);
void Mapper23_Init(CartInfo *);
void Mapper25_Init(CartInfo *);
+void Mapper28_Init(CartInfo *);
void Mapper32_Init(CartInfo *);
void Mapper33_Init(CartInfo *);
void Mapper34_Init(CartInfo *);
diff --git a/vc/vc10_fceux.vcxproj b/vc/vc10_fceux.vcxproj
index 4986faee..6350c546 100644
--- a/vc/vc10_fceux.vcxproj
+++ b/vc/vc10_fceux.vcxproj
@@ -268,6 +268,7 @@
+
diff --git a/vc/vc10_fceux.vcxproj.filters b/vc/vc10_fceux.vcxproj.filters
index 28f4a412..1ab310a7 100644
--- a/vc/vc10_fceux.vcxproj.filters
+++ b/vc/vc10_fceux.vcxproj.filters
@@ -964,6 +964,9 @@
boards
+
+ boards
+
diff --git a/vc/vc8_fceux.vcproj b/vc/vc8_fceux.vcproj
index e0f595dc..96425205 100644
--- a/vc/vc8_fceux.vcproj
+++ b/vc/vc8_fceux.vcproj
@@ -771,6 +771,10 @@
/>
+
+
diff --git a/vc/vc9_fceux.vcproj b/vc/vc9_fceux.vcproj
index 54030c49..8d1b6dc5 100644
--- a/vc/vc9_fceux.vcproj
+++ b/vc/vc9_fceux.vcproj
@@ -461,10 +461,6 @@
RelativePath="..\src\boards\222.cpp"
>
-
-
@@ -473,6 +469,10 @@
RelativePath="..\src\boards\253.cpp"
>
+
+
@@ -709,6 +709,10 @@
RelativePath="..\src\boards\tf-1201.cpp"
>
+
+