diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj
index 5809b895dd..2a0b5e19a2 100644
--- a/BizHawk.Emulation/BizHawk.Emulation.csproj
+++ b/BizHawk.Emulation/BizHawk.Emulation.csproj
@@ -138,6 +138,7 @@
Code
+
diff --git a/BizHawk.Emulation/Consoles/Nintendo/Docs/compatibility.txt b/BizHawk.Emulation/Consoles/Nintendo/Docs/compatibility.txt
index 78eeaf2948..0a1da02148 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/Docs/compatibility.txt
+++ b/BizHawk.Emulation/Consoles/Nintendo/Docs/compatibility.txt
@@ -60,7 +60,7 @@ Open bus and bus conflict emulation is not considered complete or thorough in an
070 Misc Complete
071 Camerica Complete
072 Misc (J) Nothing
-073 VRC3 Nothing
+073 VRC3 Good
074 Pirate (CN) Junk
075 VRC1 Nothing
076 Misc (J) Nothing
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC2_4.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC2_4.cs
index e98f5980ad..a50bdf383b 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC2_4.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC2_4.cs
@@ -5,7 +5,7 @@ using System.Diagnostics;
namespace BizHawk.Emulation.Consoles.Nintendo
{
//mapper 21 + 22 + 23 + 25 (docs largely in 021.txt for VRC4 and 22.txt for VRC2)
- //If you change any of the IRQ logic here, be sure to change it in VRC 6/7 as well.
+ //If you change any of the IRQ logic here, be sure to change it in VRC 3/6/7 as well.
public class VRC2_4 : NES.NESBoardBase
{
//configuration
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC3.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC3.cs
new file mode 100644
index 0000000000..fee74647e2
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC3.cs
@@ -0,0 +1,183 @@
+using System;
+using System.IO;
+using System.Diagnostics;
+
+namespace BizHawk.Emulation.Consoles.Nintendo
+{
+ //mapper 73 AKA salamander
+ //different IRQ logic than other VRC
+ public class VRC3 : NES.NESBoardBase
+ {
+ //configuration
+ int prg_bank_mask_16k;
+
+ //state
+ IntBuffer prg_banks_16k = new IntBuffer(2);
+ bool irq_mode;
+ bool irq_enabled, irq_pending, irq_autoen;
+ ushort irq_reload;
+ ushort irq_counter;
+ int irq_cycles;
+
+ public override void Dispose()
+ {
+ base.Dispose();
+ prg_banks_16k.Dispose();
+ }
+
+ public override void SyncState(Serializer ser)
+ {
+ base.SyncState(ser);
+ ser.Sync("prg_banks_16k", ref prg_banks_16k);
+ ser.Sync("irq_mode", ref irq_mode);
+ ser.Sync("irq_enabled", ref irq_enabled);
+ ser.Sync("irq_pending", ref irq_pending);
+ ser.Sync("irq_autoen", ref irq_autoen);
+ ser.Sync("irq_reload", ref irq_reload);
+ ser.Sync("irq_counter", ref irq_counter);
+ ser.Sync("irq_cycles", ref irq_cycles);
+ }
+
+ void SyncIRQ()
+ {
+ NES.irq_cart = (irq_pending && irq_enabled);
+ }
+
+ public override bool Configure(NES.EDetectionOrigin origin)
+ {
+ switch (Cart.board_type)
+ {
+ case "KONAMI-VRC-3":
+ AssertPrg(128,512); AssertChr(0,128); AssertVram(0,8); AssertWram(0,8);
+ break;
+ default:
+ return false;
+ }
+
+ prg_bank_mask_16k = Cart.prg_size / 16 - 1;
+
+ SetMirrorType(EMirrorType.Vertical);
+
+ prg_banks_16k[1] = (byte)(0xFF & prg_bank_mask_16k);
+
+ return true;
+ }
+ public override byte ReadPRG(int addr)
+ {
+ int bank_16k = addr >> 14;
+ int ofs = addr & ((1 << 14) - 1);
+ bank_16k = prg_banks_16k[bank_16k];
+ addr = (bank_16k << 14) | ofs;
+ return ROM[addr];
+ }
+
+ void WriteIrqReload(int bit, byte value)
+ {
+ int mask = 0xF << bit;
+ irq_reload = (ushort)((irq_reload & ~mask) | (value << bit));
+ }
+ public override void WritePRG(int addr, byte value)
+ {
+ switch (addr)
+ {
+ case 0x0000: WriteIrqReload(0, value); break;
+ case 0x1000: WriteIrqReload(4, value); break;
+ case 0x2000: WriteIrqReload(8, value); break;
+ case 0x3000: WriteIrqReload(12, value); break;
+
+ case 0x4000:
+ irq_mode = value.Bit(2);
+ irq_autoen = value.Bit(0);
+
+ if (value.Bit(1))
+ {
+ //enabled
+ irq_enabled = true;
+ if (irq_mode)
+ {
+ //8bit..
+ irq_counter &= 0xFF00;
+ irq_counter |= (ushort)(irq_reload & 0xFF);
+ }
+ else
+ {
+ irq_counter = irq_reload;
+ }
+ irq_cycles = 3;
+ }
+ else
+ {
+ //disabled
+ irq_enabled = false;
+ }
+
+ //acknowledge
+ irq_pending = false;
+
+ SyncIRQ();
+
+ break;
+
+ case 0x5000:
+ irq_pending = false;
+ irq_enabled = irq_autoen;
+ SyncIRQ();
+ break;
+
+ case 0x7000:
+ prg_banks_16k[0] = value & 0xF;
+ prg_banks_16k[0] &= prg_bank_mask_16k;
+ break;
+
+ }
+ }
+
+ void ClockIRQ()
+ {
+ if (irq_mode)
+ {
+ //8 bit mode
+ ushort temp = irq_counter;
+ temp &= 0xFF;
+ irq_counter &= 0xFF00;
+ if (temp == 0xFF)
+ {
+ irq_pending = true;
+ irq_counter = irq_reload;
+ irq_counter |= (ushort)(irq_reload & 0xFF);
+ SyncIRQ();
+ }
+ else
+ {
+ temp++;
+ irq_counter |= temp;
+ }
+ }
+ else
+ {
+ //16 bit mode
+ if (irq_counter == 0xFFFF)
+ {
+ irq_pending = true;
+ irq_counter = irq_reload;
+ SyncIRQ();
+ }
+ else
+ irq_counter++;
+ }
+ }
+
+ public override void ClockPPU()
+ {
+ if (!irq_enabled) return;
+
+ irq_cycles--;
+ if (irq_cycles == 0)
+ {
+ irq_cycles += 3;
+ ClockIRQ();
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC6.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC6.cs
index 514adac252..38f5f8a5ae 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC6.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC6.cs
@@ -5,7 +5,7 @@ using System.Diagnostics;
namespace BizHawk.Emulation.Consoles.Nintendo
{
//mapper 24 + 26
- //If you change any of the IRQ logic here, be sure to change it in VRC 2/4/7 as well.
+ //If you change any of the IRQ logic here, be sure to change it in VRC 2/3/4/7 as well.
public class VRC6 : NES.NESBoardBase
{
//configuration
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC7.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC7.cs
index 82d6affe43..9cb0cf02f7 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC7.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC7.cs
@@ -5,7 +5,7 @@ using System.Diagnostics;
namespace BizHawk.Emulation.Consoles.Nintendo
{
//mapper 85
- //If you change any of the IRQ logic here, be sure to change it in VRC 2/4/6 as well.
+ //If you change any of the IRQ logic here, be sure to change it in VRC 2/3/4/6 as well.
public class VRC7 : NES.NESBoardBase
{
//configuration