diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj
index 6dde8e636a..f9c68fe7ba 100644
--- a/BizHawk.Emulation/BizHawk.Emulation.csproj
+++ b/BizHawk.Emulation/BizHawk.Emulation.csproj
@@ -152,6 +152,7 @@
+
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper027.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper027.cs
new file mode 100644
index 0000000000..bf4e2376f3
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper027.cs
@@ -0,0 +1,154 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace BizHawk.Emulation.Consoles.Nintendo
+{
+ // World Hero (Unl)
+ // 8k banked prgrom, 1k banked chrrom, scanline counter
+ // tried to copy behavior from fceux, but it doesn't work
+ public class Mapper027 : NES.NESBoardBase
+ {
+ // state
+ int[] chr = new int[8];
+ int[] prg = new int[4];
+ int prglatch;
+ int irqlatch;
+ int irqstat;
+ int irqcount;
+
+ // config
+ int chr_mask;
+ int prg_mask;
+
+ public override bool Configure(NES.EDetectionOrigin origin)
+ {
+ switch (Cart.board_type)
+ {
+ case "MAPPER027":
+ break;
+ default:
+ return false;
+ }
+ AssertPrg(128);
+ AssertChr(512);
+ AssertVram(0);
+ AssertWram(0);
+ prg_mask = Cart.prg_size / 8 - 1;
+ chr_mask = Cart.chr_size / 1 - 1;
+ prg[3] = prg_mask;
+ return true;
+ }
+
+ public override byte ReadPRG(int addr)
+ {
+ return ROM[addr & 0x1fff | prg[addr >> 13] << 13];
+ }
+
+ public override byte ReadPPU(int addr)
+ {
+ if (addr < 0x2000)
+ return VROM[addr & 0x3ff | chr[addr >> 10] << 10];
+ else
+ return base.ReadPPU(addr);
+ }
+
+ public override void WritePRG(int addr, byte value)
+ {
+ addr &= 0xf00f;
+ //if (true)
+ // Console.WriteLine("{0:x4}:{1:x2}", addr + 0x8000, value);
+ if (addr >= 0x3000 && addr <= 0x6003)
+ {
+ int regnum = (addr >> 12) + 1 & 3;
+ regnum = regnum << 1 | (addr & 2) >> 1;
+ if ((addr & 1) != 0)
+ {
+ chr[regnum] &= 0x00f;
+ chr[regnum] |= value << 4 & chr_mask;
+ }
+ else
+ {
+ chr[regnum] &= 0x1f0;
+ chr[regnum] |= value & 0xf & chr_mask;
+ }
+ return;
+ }
+
+ switch (addr)
+ {
+ case 0x0000:
+ prg[prglatch] = value & prg_mask;
+ break;
+ case 0x1000:
+ switch (value & 3)
+ {
+ case 0: SetMirrorType(EMirrorType.Vertical); break;
+ case 1: SetMirrorType(EMirrorType.Horizontal); break;
+ case 2: SetMirrorType(EMirrorType.OneScreenA); break;
+ case 3: SetMirrorType(EMirrorType.OneScreenB); break;
+ }
+ prglatch = value & 2; // in fceux, this runs because of a lack of case break. bug?
+ break;
+ case 0x1002:
+ prglatch = value & 2;
+ break;
+ case 0x2000:
+ prg[1] = value & prg_mask;
+ break;
+ case 0x7000:
+ irqlatch &= 0xf0;
+ irqlatch |= value & 0x0f;
+ break;
+ case 0x7001:
+ irqlatch &= 0x0f;
+ irqlatch |= value << 4 & 0xf0;
+ break;
+ case 0x7002:
+ irqstat = value & 3;
+ if ((irqstat & 2) != 0)
+ irqcount = irqlatch - 1;
+ break;
+ case 0x7003:
+ irqstat = irqstat << 1 & 2 | irqstat & 1;
+ IRQSignal = false;
+ break;
+ }
+
+
+ }
+
+ // irq timing is entirely a guess; this bit improvised from ExROM
+ public override void ClockPPU()
+ {
+ if (NES.ppu.ppur.status.cycle != 336)
+ return;
+ if (!NES.ppu.reg_2001.PPUON)
+ return;
+
+ int sl = NES.ppu.ppur.status.sl + 1;
+
+ if (sl >= 241)
+ return;
+ hblanktrigger();
+ }
+
+ void hblanktrigger()
+ {
+ if ((irqstat & 2) != 0)
+ {
+ if (irqcount == 255)
+ {
+ IRQSignal = true;
+ irqcount = irqlatch + 1;
+ Console.WriteLine("Raise");
+ }
+ else
+ irqcount++;
+ }
+ }
+
+
+ }
+}